diff --git a/ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch b/ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch deleted file mode 100644 index 28579d13b..000000000 --- a/ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch +++ /dev/null @@ -1,37 +0,0 @@ -From a9e1e167d934aa74f48008393ade4f09fc587432 Mon Sep 17 00:00:00 2001 -From: Josh Boyer -Date: Thu, 12 Apr 2012 13:55:36 -0400 -Subject: [PATCH] ALSA: hda/realtek - Add quirk for Mac Pro 5,1 machines - -A user reported that setting model=imac24 used to allow sound to work on their -Mac Pro 5,1 machine. Commit 5671087ffa "Move ALC885 macpro and imac24 models -to auto-parser" removed this model option. All Mac machines are now explicitly -handled with a quirk and the auto-parser. This adds a quirk for the device -found on the Mac Pro 5,1 machines. - -This (partially) fixes https://bugzilla.redhat.com/show_bug.cgi?id=808559 - -[sorted the new entry in the ID number order by tiwai] - -Reported-by: Gabriel Somlo -Signed-off-by: Josh Boyer -Signed-off-by: Takashi Iwai ---- - sound/pci/hda/patch_realtek.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c -index 22c73b7..bd34b51 100644 ---- a/sound/pci/hda/patch_realtek.c -+++ b/sound/pci/hda/patch_realtek.c -@@ -4659,6 +4659,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { - SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), - SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO), -+ SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO), - - SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), --- -1.7.7.6 - diff --git a/NFS-optimise-away-unnecessary-setattrs-for-open-O_TRUNC.patch b/NFS-optimise-away-unnecessary-setattrs-for-open-O_TRUNC.patch deleted file mode 100644 index 89b6308cd..000000000 --- a/NFS-optimise-away-unnecessary-setattrs-for-open-O_TRUNC.patch +++ /dev/null @@ -1,153 +0,0 @@ -From: Trond Myklebust - -Currently, we will correctly optimise away a truncate that doesn't -change the file size. However, in the case of open(O_TRUNC), we -also want to optimise away the time changes. - -Signed-off-by: Trond Myklebust ---- - fs/nfs/dir.c | 25 +++++++++++++++++++------ - fs/nfs/inode.c | 4 ++-- - fs/nfs/nfs4proc.c | 10 +++++++--- - 3 files changed, 28 insertions(+), 11 deletions(-) - -diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c -index fd9a872..bb132a8 100644 ---- a/fs/nfs/dir.c -+++ b/fs/nfs/dir.c -@@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry - } - - open_flags = nd->intent.open.flags; -+ attr.ia_valid = 0; - - ctx = create_nfs_open_context(dentry, open_flags); - res = ERR_CAST(ctx); -@@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry - - if (nd->flags & LOOKUP_CREATE) { - attr.ia_mode = nd->intent.open.create_mode; -- attr.ia_valid = ATTR_MODE; -+ attr.ia_valid |= ATTR_MODE; - attr.ia_mode &= ~current_umask(); -- } else { -+ } else - open_flags &= ~(O_EXCL | O_CREAT); -- attr.ia_valid = 0; -+ -+ if (open_flags & O_TRUNC) { -+ attr.ia_valid |= ATTR_SIZE; -+ attr.ia_size = 0; - } - - /* Open the file on the server */ -@@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) - struct inode *inode; - struct inode *dir; - struct nfs_open_context *ctx; -+ struct iattr attr; - int openflags, ret = 0; - - if (nd->flags & LOOKUP_RCU) -@@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) - /* We cannot do exclusive creation on a positive dentry */ - if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) - goto no_open_dput; -- /* We can't create new files, or truncate existing ones here */ -- openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); -+ /* We can't create new files here */ -+ openflags &= ~(O_CREAT|O_EXCL); - - ctx = create_nfs_open_context(dentry, openflags); - ret = PTR_ERR(ctx); - if (IS_ERR(ctx)) - goto out; -+ -+ attr.ia_valid = 0; -+ if (openflags & O_TRUNC) { -+ attr.ia_valid |= ATTR_SIZE; -+ attr.ia_size = 0; -+ nfs_wb_all(inode); -+ } -+ - /* - * Note: we're not holding inode->i_mutex and so may be racing with - * operations that change the directory. We therefore save the - * change attribute *before* we do the RPC call. - */ -- inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL); -+ inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr); - if (IS_ERR(inode)) { - ret = PTR_ERR(inode); - switch (ret) { -diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c -index f649fba..57d0abb 100644 ---- a/fs/nfs/inode.c -+++ b/fs/nfs/inode.c -@@ -401,7 +401,7 @@ out_no_inode: - goto out; - } - --#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE) -+#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN) - - int - nfs_setattr(struct dentry *dentry, struct iattr *attr) -@@ -423,7 +423,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) - - /* Optimization: if the end result is no change, don't RPC */ - attr->ia_valid &= NFS_VALID_ATTRS; -- if ((attr->ia_valid & ~ATTR_FILE) == 0) -+ if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0) - return 0; - - /* Write all dirty data */ -diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c -index 1515e45..c4c6b48 100644 ---- a/fs/nfs/nfs4proc.c -+++ b/fs/nfs/nfs4proc.c -@@ -833,7 +833,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, - p->o_arg.bitmask = server->attr_bitmask; - p->o_arg.dir_bitmask = server->cache_consistency_bitmask; - p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; -- if (flags & O_CREAT) { -+ if (attrs != NULL && attrs->ia_valid != 0) { - u32 *s; - - p->o_arg.u.attrs = &p->attrs; -@@ -890,7 +890,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode - { - int ret = 0; - -- if (open_mode & O_EXCL) -+ if (open_mode & (O_EXCL|O_TRUNC)) - goto out; - switch (mode & (FMODE_READ|FMODE_WRITE)) { - case FMODE_READ: -@@ -1038,7 +1038,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) - struct nfs4_state *state = opendata->state; - struct nfs_inode *nfsi = NFS_I(state->inode); - struct nfs_delegation *delegation; -- int open_mode = opendata->o_arg.open_flags & O_EXCL; -+ int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC); - fmode_t fmode = opendata->o_arg.fmode; - nfs4_stateid stateid; - int ret = -EAGAIN; -@@ -2439,6 +2439,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, - } - } - -+ /* Deal with open(O_TRUNC) */ -+ if (sattr->ia_valid & ATTR_OPEN) -+ sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN); -+ - status = nfs4_do_setattr(inode, cred, fattr, sattr, state); - if (status == 0) - nfs_setattr_update_inode(inode, sattr); --- -1.7.7.6 - -_______________________________________________ -kernel mailing list -kernel@lists.fedoraproject.org -https://admin.fedoraproject.org/mailman/listinfo/kernel diff --git a/NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch b/NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch deleted file mode 100644 index 42d1052e2..000000000 --- a/NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch +++ /dev/null @@ -1,109 +0,0 @@ -diff -up linux-3.2.noarch/fs/nfs/idmap.c.orig linux-3.2.noarch/fs/nfs/idmap.c ---- linux-3.2.noarch/fs/nfs/idmap.c.orig 2012-03-14 13:08:37.462928792 -0400 -+++ linux-3.2.noarch/fs/nfs/idmap.c 2012-03-14 13:10:17.076030982 -0400 -@@ -365,7 +365,7 @@ struct idmap_hashent { - - struct idmap_hashtable { - __u8 h_type; -- struct idmap_hashent h_entries[IDMAP_HASH_SZ]; -+ struct idmap_hashent *h_entries; - }; - - struct idmap { -@@ -420,20 +420,39 @@ nfs_idmap_new(struct nfs_client *clp) - return 0; - } - -+static void -+idmap_alloc_hashtable(struct idmap_hashtable *h) -+{ -+ if (h->h_entries != NULL) -+ return; -+ h->h_entries = kcalloc(IDMAP_HASH_SZ, -+ sizeof(*h->h_entries), -+ GFP_KERNEL); -+} -+ -+static void -+idmap_free_hashtable(struct idmap_hashtable *h) -+{ -+ int i; -+ -+ if (h->h_entries == NULL) -+ return; -+ for (i = 0; i < IDMAP_HASH_SZ; i++) -+ kfree(h->h_entries[i].ih_name); -+ kfree(h->h_entries); -+} -+ - void - nfs_idmap_delete(struct nfs_client *clp) - { - struct idmap *idmap = clp->cl_idmap; -- int i; - - if (!idmap) - return; - rpc_unlink(idmap->idmap_dentry); - clp->cl_idmap = NULL; -- for (i = 0; i < ARRAY_SIZE(idmap->idmap_user_hash.h_entries); i++) -- kfree(idmap->idmap_user_hash.h_entries[i].ih_name); -- for (i = 0; i < ARRAY_SIZE(idmap->idmap_group_hash.h_entries); i++) -- kfree(idmap->idmap_group_hash.h_entries[i].ih_name); -+ idmap_free_hashtable(&idmap->idmap_user_hash); -+ idmap_free_hashtable(&idmap->idmap_group_hash); - kfree(idmap); - } - -@@ -443,6 +462,8 @@ nfs_idmap_delete(struct nfs_client *clp) - static inline struct idmap_hashent * - idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len) - { -+ if (h->h_entries == NULL) -+ return NULL; - return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ]; - } - -@@ -451,6 +472,8 @@ idmap_lookup_name(struct idmap_hashtable - { - struct idmap_hashent *he = idmap_name_hash(h, name, len); - -+ if (he == NULL) -+ return NULL; - if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) - return NULL; - if (time_after(jiffies, he->ih_expires)) -@@ -461,6 +484,8 @@ idmap_lookup_name(struct idmap_hashtable - static inline struct idmap_hashent * - idmap_id_hash(struct idmap_hashtable* h, __u32 id) - { -+ if (h->h_entries == NULL) -+ return NULL; - return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ]; - } - -@@ -468,6 +493,9 @@ static struct idmap_hashent * - idmap_lookup_id(struct idmap_hashtable *h, __u32 id) - { - struct idmap_hashent *he = idmap_id_hash(h, id); -+ -+ if (he == NULL) -+ return NULL; - if (he->ih_id != id || he->ih_namelen == 0) - return NULL; - if (time_after(jiffies, he->ih_expires)) -@@ -483,12 +511,14 @@ idmap_lookup_id(struct idmap_hashtable * - static inline struct idmap_hashent * - idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len) - { -+ idmap_alloc_hashtable(h); - return idmap_name_hash(h, name, len); - } - - static inline struct idmap_hashent * - idmap_alloc_id(struct idmap_hashtable *h, __u32 id) - { -+ idmap_alloc_hashtable(h); - return idmap_id_hash(h, id); - } - diff --git a/NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch b/NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch deleted file mode 100644 index 105235126..000000000 --- a/NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 14977489ffdb80d4caf5a184ba41b23b02fbacd9 Mon Sep 17 00:00:00 2001 -From: Trond Myklebust -Date: Tue, 27 Mar 2012 18:31:25 -0400 -Subject: [PATCH] NFSv4: Minor cleanups for nfs4_handle_exception and - nfs4_async_handle_error - -Signed-off-by: Trond Myklebust ---- - fs/nfs/nfs4proc.c | 10 +++++----- - 1 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c -index 1933e67..f82bde0 100644 ---- a/fs/nfs/nfs4proc.c -+++ b/fs/nfs/nfs4proc.c -@@ -270,7 +270,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc - case 0: - return 0; - case -NFS4ERR_OPENMODE: -- if (nfs_have_delegation(inode, FMODE_READ)) { -+ if (inode && nfs_have_delegation(inode, FMODE_READ)) { - nfs_inode_return_delegation(inode); - exception->retry = 1; - return 0; -@@ -282,10 +282,9 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc - case -NFS4ERR_DELEG_REVOKED: - case -NFS4ERR_ADMIN_REVOKED: - case -NFS4ERR_BAD_STATEID: -- if (state != NULL) -- nfs_remove_bad_delegation(state->inode); - if (state == NULL) - break; -+ nfs_remove_bad_delegation(state->inode); - nfs4_schedule_stateid_recovery(server, state); - goto wait_on_recovery; - case -NFS4ERR_EXPIRED: -@@ -3825,8 +3824,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, - case -NFS4ERR_DELEG_REVOKED: - case -NFS4ERR_ADMIN_REVOKED: - case -NFS4ERR_BAD_STATEID: -- if (state != NULL) -- nfs_remove_bad_delegation(state->inode); -+ if (state == NULL) -+ break; -+ nfs_remove_bad_delegation(state->inode); - case -NFS4ERR_OPENMODE: - if (state == NULL) - break; --- -1.7.7.6 - diff --git a/NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch b/NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch deleted file mode 100644 index 5b7f5e51d..000000000 --- a/NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 34d91cfbc163c6e2a136a27c96918fc35de06341 Mon Sep 17 00:00:00 2001 -From: William Dauchy -Date: Wed, 14 Mar 2012 12:32:04 +0100 -Subject: [PATCH] NFSv4: Rate limit the state manager for lock reclaim warning - messages - -Adding rate limit on `Lock reclaim failed` messages since it could fill -up system logs -Signed-off-by: William Dauchy -Signed-off-by: Trond Myklebust - -Conflicts: - - fs/nfs/nfs4state.c ---- - fs/nfs/nfs4state.c | 5 +++-- - 1 files changed, 3 insertions(+), 2 deletions(-) - -diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c -index bacb271..3676b5c 100644 ---- a/fs/nfs/nfs4state.c -+++ b/fs/nfs/nfs4state.c -@@ -1247,8 +1247,9 @@ restart: - spin_lock(&state->state_lock); - list_for_each_entry(lock, &state->lock_states, ls_locks) { - if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) -- printk("%s: Lock reclaim failed!\n", -- __func__); -+ pr_warn_ratelimited("NFS: " -+ "%s: Lock reclaim " -+ "failed!\n", __func__); - } - spin_unlock(&state->state_lock); - nfs4_put_open_state(state); --- -1.7.7.6 - diff --git a/NFSv4-Reduce-the-footprint-of-the-idmapper.patch b/NFSv4-Reduce-the-footprint-of-the-idmapper.patch deleted file mode 100644 index 4110ef904..000000000 --- a/NFSv4-Reduce-the-footprint-of-the-idmapper.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff -up linux-3.2.noarch/fs/nfs/idmap.c.orig linux-3.2.noarch/fs/nfs/idmap.c ---- linux-3.2.noarch/fs/nfs/idmap.c.orig 2012-02-07 07:12:52.585471833 -0500 -+++ linux-3.2.noarch/fs/nfs/idmap.c 2012-03-14 13:08:37.462928792 -0400 -@@ -360,7 +360,7 @@ struct idmap_hashent { - unsigned long ih_expires; - __u32 ih_id; - size_t ih_namelen; -- char ih_name[IDMAP_NAMESZ]; -+ const char *ih_name; - }; - - struct idmap_hashtable { -@@ -424,11 +424,16 @@ void - nfs_idmap_delete(struct nfs_client *clp) - { - struct idmap *idmap = clp->cl_idmap; -+ int i; - - if (!idmap) - return; - rpc_unlink(idmap->idmap_dentry); - clp->cl_idmap = NULL; -+ for (i = 0; i < ARRAY_SIZE(idmap->idmap_user_hash.h_entries); i++) -+ kfree(idmap->idmap_user_hash.h_entries[i].ih_name); -+ for (i = 0; i < ARRAY_SIZE(idmap->idmap_group_hash.h_entries); i++) -+ kfree(idmap->idmap_group_hash.h_entries[i].ih_name); - kfree(idmap); - } - -@@ -491,9 +496,14 @@ static void - idmap_update_entry(struct idmap_hashent *he, const char *name, - size_t namelen, __u32 id) - { -+ char *str = kmalloc(namelen + 1, GFP_KERNEL); -+ if (str == NULL) -+ return; -+ kfree(he->ih_name); - he->ih_id = id; -- memcpy(he->ih_name, name, namelen); -- he->ih_name[namelen] = '\0'; -+ memcpy(str, name, namelen); -+ str[namelen] = '\0'; -+ he->ih_name = str; - he->ih_namelen = namelen; - he->ih_expires = jiffies + nfs_idmap_cache_timeout; - } diff --git a/NFSv4-fix-open-O_TRUNC-and-ftruncate-error-handling.patch b/NFSv4-fix-open-O_TRUNC-and-ftruncate-error-handling.patch deleted file mode 100644 index 134b210fe..000000000 --- a/NFSv4-fix-open-O_TRUNC-and-ftruncate-error-handling.patch +++ /dev/null @@ -1,69 +0,0 @@ -From: Trond Myklebust - -If the file wasn't opened for writing, then truncate and ftruncate -need to report the appropriate errors. - -Reported-by: Miklos Szeredi -Signed-off-by: Trond Myklebust -Cc: stable@vger.kernel.org ---- - fs/nfs/dir.c | 4 ++-- - fs/nfs/nfs4proc.c | 15 ++++++++++++--- - 2 files changed, 14 insertions(+), 5 deletions(-) - -diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c -index bb132a8..51a2686 100644 ---- a/fs/nfs/dir.c -+++ b/fs/nfs/dir.c -@@ -1429,7 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry - } - - open_flags = nd->intent.open.flags; -- attr.ia_valid = 0; -+ attr.ia_valid = ATTR_OPEN; - - ctx = create_nfs_open_context(dentry, open_flags); - res = ERR_CAST(ctx); -@@ -1536,7 +1536,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) - if (IS_ERR(ctx)) - goto out; - -- attr.ia_valid = 0; -+ attr.ia_valid = ATTR_OPEN; - if (openflags & O_TRUNC) { - attr.ia_valid |= ATTR_SIZE; - attr.ia_size = 0; -diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c -index c4c6b48..e2a2893 100644 ---- a/fs/nfs/nfs4proc.c -+++ b/fs/nfs/nfs4proc.c -@@ -1921,10 +1921,19 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, - }; - int err; - do { -- err = nfs4_handle_exception(server, -- _nfs4_do_setattr(inode, cred, fattr, sattr, state), -- &exception); -+ err = _nfs4_do_setattr(inode, cred, fattr, sattr, state); -+ switch (err) { -+ case -NFS4ERR_OPENMODE: -+ if (state && !(state->state & FMODE_WRITE)) { -+ err = -EBADF; -+ if (sattr->ia_valid & ATTR_OPEN) -+ err = -EACCES; -+ goto out; -+ } -+ } -+ err = nfs4_handle_exception(server, err, &exception); - } while (exception.retry); -+out: - return err; - } - --- -1.7.7.6 - -_______________________________________________ -kernel mailing list -kernel@lists.fedoraproject.org -https://admin.fedoraproject.org/mailman/listinfo/kernel diff --git a/SUNRPC-move-per-net-operations-from-svc_destroy.patch b/SUNRPC-move-per-net-operations-from-svc_destroy.patch new file mode 100644 index 000000000..1895b5bca --- /dev/null +++ b/SUNRPC-move-per-net-operations-from-svc_destroy.patch @@ -0,0 +1,327 @@ +Path: news.gmane.org!not-for-mail +From: Stanislav Kinsbursky +Newsgroups: gmane.linux.kernel,gmane.linux.nfs,gmane.linux.openvz.devel +Subject: [PATCH 2/2] SUNRPC: move per-net operations from svc_destroy() +Date: Fri, 01 Jun 2012 15:17:50 +0400 +Lines: 281 +Approved: news@gmane.org +Message-ID: <20120601111750.7846.23782.stgit@localhost.localdomain> +References: <20120601111619.7846.95457.stgit@localhost.localdomain> +NNTP-Posting-Host: plane.gmane.org +Mime-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit +X-Trace: dough.gmane.org 1338549639 9108 80.91.229.3 (1 Jun 2012 11:20:39 GMT) +X-Complaints-To: usenet@dough.gmane.org +NNTP-Posting-Date: Fri, 1 Jun 2012 11:20:39 +0000 (UTC) +Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, + devel@openvz.org +To: bfields@fieldses.org, Trond.Myklebust@netapp.com +Original-X-From: linux-kernel-owner@vger.kernel.org Fri Jun 01 13:20:37 2012 +Return-path: +Envelope-to: glk-linux-kernel-3@plane.gmane.org +Original-Received: from vger.kernel.org ([209.132.180.67]) + by plane.gmane.org with esmtp (Exim 4.69) + (envelope-from ) + id 1SaPuE-0002JL-ED + for glk-linux-kernel-3@plane.gmane.org; Fri, 01 Jun 2012 13:20:34 +0200 +Original-Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S1759489Ab2FALUJ (ORCPT ); + Fri, 1 Jun 2012 07:20:09 -0400 +Original-Received: from mailhub.sw.ru ([195.214.232.25]:7947 "EHLO relay.sw.ru" + rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP + id S1759474Ab2FALUE (ORCPT ); + Fri, 1 Jun 2012 07:20:04 -0400 +Original-Received: from localhost.localdomain ([10.30.21.131]) + by relay.sw.ru (8.13.4/8.13.4) with ESMTP id q51BJrkd020556; + Fri, 1 Jun 2012 15:19:54 +0400 (MSK) +In-Reply-To: <20120601111619.7846.95457.stgit@localhost.localdomain> +User-Agent: StGit/0.16 +Original-Sender: linux-kernel-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-kernel@vger.kernel.org +Xref: news.gmane.org gmane.linux.kernel:1306567 gmane.linux.nfs:50236 gmane.linux.openvz.devel:1597 +Archived-At: + +This patch was back-ported from 3.5 kernel. + +The idea is to separate service destruction and per-net operations, because +these are two different things and it's mix looks ugly. + +Notes: +1) For NFS server this patch looks ugly (sorry for that). But these place will +be +rewritten soon during NFSd containerization. +2) LockD per-net counter increase int lockd_up() was moved prior to +make_socks() to make lockd_down_net() call safe in case of error. + +Signed-off-by: Stanislav Kinsbursky +--- + fs/lockd/svc.c | 27 +++++++++++++++------------ + fs/nfs/callback.c | 3 +++ + fs/nfsd/nfsctl.c | 12 +++++++++--- + fs/nfsd/nfssvc.c | 14 ++++++++++++++ + net/sunrpc/svc.c | 4 ---- + 5 files changed, 41 insertions(+), 19 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index b1d0708..f1b3cce 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -257,7 +257,7 @@ static int lockd_up_net(struct net *net) + struct svc_serv *serv = nlmsvc_rqst->rq_server; + int error; + +- if (ln->nlmsvc_users) ++ if (ln->nlmsvc_users++) + return 0; + + error = svc_rpcb_setup(serv, net); +@@ -272,6 +272,7 @@ static int lockd_up_net(struct net *net) + err_socks: + svc_rpcb_cleanup(serv, net); + err_rpcb: ++ ln->nlmsvc_users--; + return error; + } + +@@ -300,6 +301,7 @@ int lockd_up(void) + struct svc_serv *serv; + int error = 0; + struct net *net = current->nsproxy->net_ns; ++ struct lockd_net *ln = net_generic(net, lockd_net_id); + + mutex_lock(&nlmsvc_mutex); + /* +@@ -331,9 +333,11 @@ int lockd_up(void) + goto destroy_and_out; + } + ++ ln->nlmsvc_users++; ++ + error = make_socks(serv, net); + if (error < 0) +- goto destroy_and_out; ++ goto err_start; + + /* + * Create the kernel thread and wait for it to start. +@@ -345,7 +349,7 @@ int lockd_up(void) + printk(KERN_WARNING + "lockd_up: svc_rqst allocation failed, error=%d\n", + error); +- goto destroy_and_out; ++ goto err_start; + } + + svc_sock_update_bufs(serv); +@@ -359,7 +363,7 @@ int lockd_up(void) + nlmsvc_rqst = NULL; + printk(KERN_WARNING + "lockd_up: kthread_run failed, error=%d\n", error); +- goto destroy_and_out; ++ goto err_start; + } + + /* +@@ -369,14 +373,14 @@ int lockd_up(void) + destroy_and_out: + svc_destroy(serv); + out: +- if (!error) { +- struct lockd_net *ln = net_generic(net, lockd_net_id); +- +- ln->nlmsvc_users++; ++ if (!error) + nlmsvc_users++; +- } + mutex_unlock(&nlmsvc_mutex); + return error; ++ ++err_start: ++ lockd_down_net(net); ++ goto destroy_and_out; + } + EXPORT_SYMBOL_GPL(lockd_up); + +@@ -387,11 +391,10 @@ void + lockd_down(void) + { + mutex_lock(&nlmsvc_mutex); ++ lockd_down_net(current->nsproxy->net_ns); + if (nlmsvc_users) { +- if (--nlmsvc_users) { +- lockd_down_net(current->nsproxy->net_ns); ++ if (--nlmsvc_users) + goto out; +- } + } else { + printk(KERN_ERR "lockd_down: no users! task=%p\n", + nlmsvc_task); +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 0563237..38a44c6 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -313,6 +313,8 @@ out_err: + dprintk("NFS: Couldn't create callback socket or server thread; " + "err = %d\n", ret); + cb_info->users--; ++ if (serv) ++ svc_shutdown_net(serv, net); + goto out; + } + +@@ -327,6 +329,7 @@ void nfs_callback_down(int minorversion) + cb_info->users--; + if (cb_info->users == 0 && cb_info->task != NULL) { + kthread_stop(cb_info->task); ++ svc_shutdown_net(cb_info->serv, &init_net); + svc_exit_thread(cb_info->rqst); + cb_info->serv = NULL; + cb_info->rqst = NULL; +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 2c53be6..3ab12eb 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -651,6 +651,7 @@ static ssize_t __write_ports_addfd(char *buf) + { + char *mesg = buf; + int fd, err; ++ struct net *net = &init_net; + + err = get_int(&mesg, &fd); + if (err != 0 || fd < 0) +@@ -662,6 +663,8 @@ static ssize_t __write_ports_addfd(char *buf) + + err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); + if (err < 0) { ++ if (nfsd_serv->sv_nrthreads == 1) ++ svc_shutdown_net(nfsd_serv, net); + svc_destroy(nfsd_serv); + return err; + } +@@ -699,6 +702,7 @@ static ssize_t __write_ports_addxprt(char *buf) + char transport[16]; + struct svc_xprt *xprt; + int port, err; ++ struct net *net = &init_net; + + if (sscanf(buf, "%15s %4u", transport, &port) != 2) + return -EINVAL; +@@ -710,12 +714,12 @@ static ssize_t __write_ports_addxprt(char *buf) + if (err != 0) + return err; + +- err = svc_create_xprt(nfsd_serv, transport, &init_net, ++ err = svc_create_xprt(nfsd_serv, transport, net, + PF_INET, port, SVC_SOCK_ANONYMOUS); + if (err < 0) + goto out_err; + +- err = svc_create_xprt(nfsd_serv, transport, &init_net, ++ err = svc_create_xprt(nfsd_serv, transport, net, + PF_INET6, port, SVC_SOCK_ANONYMOUS); + if (err < 0 && err != -EAFNOSUPPORT) + goto out_close; +@@ -724,12 +728,14 @@ static ssize_t __write_ports_addxprt(char *buf) + nfsd_serv->sv_nrthreads--; + return 0; + out_close: +- xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); ++ xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port); + if (xprt != NULL) { + svc_close_xprt(xprt); + svc_xprt_put(xprt); + } + out_err: ++ if (nfsd_serv->sv_nrthreads == 1) ++ svc_shutdown_net(nfsd_serv, net); + svc_destroy(nfsd_serv); + return err; + } +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index a6461f3..da50e1c 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -382,6 +382,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) + int i = 0; + int tot = 0; + int err = 0; ++ struct net *net = &init_net; + + WARN_ON(!mutex_is_locked(&nfsd_mutex)); + +@@ -426,6 +427,9 @@ int nfsd_set_nrthreads(int n, int *nthreads) + if (err) + break; + } ++ ++ if (nfsd_serv->sv_nrthreads == 1) ++ svc_shutdown_net(nfsd_serv, net); + svc_destroy(nfsd_serv); + + return err; +@@ -441,6 +445,7 @@ nfsd_svc(unsigned short port, int nrservs) + { + int error; + bool nfsd_up_before; ++ struct net *net = &init_net; + + mutex_lock(&nfsd_mutex); + dprintk("nfsd: creating service\n"); +@@ -473,6 +478,8 @@ out_shutdown: + if (error < 0 && !nfsd_up_before) + nfsd_shutdown(); + out_destroy: ++ if (nfsd_serv->sv_nrthreads == 1) ++ svc_shutdown_net(nfsd_serv, net); + svc_destroy(nfsd_serv); /* Release server */ + out: + mutex_unlock(&nfsd_mutex); +@@ -556,6 +563,9 @@ nfsd(void *vrqstp) + nfsdstats.th_cnt --; + + out: ++ if (rqstp->rq_server->sv_nrthreads == 1) ++ svc_shutdown_net(rqstp->rq_server, &init_net); ++ + /* Release the thread */ + svc_exit_thread(rqstp); + +@@ -668,8 +678,12 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file) + int nfsd_pool_stats_release(struct inode *inode, struct file *file) + { + int ret = seq_release(inode, file); ++ struct net *net = &init_net; ++ + mutex_lock(&nfsd_mutex); + /* this function really, really should have been called svc_put() */ ++ if (nfsd_serv->sv_nrthreads == 1) ++ svc_shutdown_net(nfsd_serv, net); + svc_destroy(nfsd_serv); + mutex_unlock(&nfsd_mutex); + return ret; +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index e6d542c..b7210f5 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -537,8 +537,6 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net); + void + svc_destroy(struct svc_serv *serv) + { +- struct net *net = current->nsproxy->net_ns; +- + dprintk("svc: svc_destroy(%s, %d)\n", + serv->sv_program->pg_name, + serv->sv_nrthreads); +@@ -553,8 +551,6 @@ svc_destroy(struct svc_serv *serv) + + del_timer_sync(&serv->sv_temptimer); + +- svc_shutdown_net(serv, net); +- + /* + * The last user is gone and thus all sockets have to be destroyed to + * the point. Check this. + diff --git a/SUNRPC-new-svc_bind-routine-introduced.patch b/SUNRPC-new-svc_bind-routine-introduced.patch new file mode 100644 index 000000000..58127cca0 --- /dev/null +++ b/SUNRPC-new-svc_bind-routine-introduced.patch @@ -0,0 +1,249 @@ +Path: news.gmane.org!not-for-mail +From: Stanislav Kinsbursky +Newsgroups: gmane.linux.nfs,gmane.linux.kernel,gmane.linux.openvz.devel +Subject: [PATCH 1/2] SUNRPC: new svc_bind() routine introduced +Date: Fri, 01 Jun 2012 15:17:42 +0400 +Lines: 203 +Approved: news@gmane.org +Message-ID: <20120601111742.7846.99872.stgit@localhost.localdomain> +References: <20120601111619.7846.95457.stgit@localhost.localdomain> +NNTP-Posting-Host: plane.gmane.org +Mime-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit +X-Trace: dough.gmane.org 1338549604 8815 80.91.229.3 (1 Jun 2012 11:20:04 GMT) +X-Complaints-To: usenet@dough.gmane.org +NNTP-Posting-Date: Fri, 1 Jun 2012 11:20:04 +0000 (UTC) +Cc: linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, + devel-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org +To: bfields-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org, Trond.Myklebust-HgOvQuBEEgTQT0dZR+AlfA@public.gmane.org +Original-X-From: linux-nfs-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org Fri Jun 01 13:20:02 2012 +Return-path: +Envelope-to: glN-linux-nfs-wOFGN7rlS/M9smdsby/KFg@public.gmane.org +Original-Received: from vger.kernel.org ([209.132.180.67]) + by plane.gmane.org with esmtp (Exim 4.69) + (envelope-from ) + id 1SaPtg-0001Xs-F8 + for glN-linux-nfs-wOFGN7rlS/M9smdsby/KFg@public.gmane.org; Fri, 01 Jun 2012 13:20:00 +0200 +Original-Received: (majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org) by vger.kernel.org via listexpand + id S1759450Ab2FALT7 (ORCPT ); + Fri, 1 Jun 2012 07:19:59 -0400 +Original-Received: from mailhub.sw.ru ([195.214.232.25]:20534 "EHLO relay.sw.ru" + rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP + id S1759448Ab2FALT6 (ORCPT ); + Fri, 1 Jun 2012 07:19:58 -0400 +Original-Received: from localhost.localdomain ([10.30.21.131]) + by relay.sw.ru (8.13.4/8.13.4) with ESMTP id q51BJjDD010948; + Fri, 1 Jun 2012 15:19:46 +0400 (MSK) +In-Reply-To: <20120601111619.7846.95457.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> +User-Agent: StGit/0.16 +Original-Sender: linux-nfs-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org +Xref: news.gmane.org gmane.linux.nfs:50234 gmane.linux.kernel:1306565 gmane.linux.openvz.devel:1595 +Archived-At: + +This patch was back-ported from 3.5 kernel. + +New routine is responsible for service registration in specified network +context. +The idea is to separate service creation from per-net operations. +Since registering service with svc_bind() can fail, then service will be +destroyed and during destruction it will try to unregister itself from +rpcbind. In this case unregister have to be skipped. + +Signed-off-by: Stanislav Kinsbursky +--- + fs/lockd/svc.c | 6 ++++++ + fs/nfs/callback.c | 13 ++++++++++--- + fs/nfsd/nfssvc.c | 9 +++++++++ + include/linux/sunrpc/svc.h | 1 + + net/sunrpc/rpcb_clnt.c | 12 +++++++----- + net/sunrpc/svc.c | 19 ++++++++++--------- + 6 files changed, 43 insertions(+), 17 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index f49b9af..b1d0708 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -325,6 +325,12 @@ int lockd_up(void) + goto out; + } + ++ error = svc_bind(serv, net); ++ if (error < 0) { ++ printk(KERN_WARNING "lockd_up: bind service failed\n"); ++ goto destroy_and_out; ++ } ++ + error = make_socks(serv, net); + if (error < 0) + goto destroy_and_out; +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index eb95f50..0563237 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -106,7 +106,7 @@ nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) + { + int ret; + +- ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET, ++ ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET, + nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); + if (ret <= 0) + goto out_err; +@@ -114,7 +114,7 @@ nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) + dprintk("NFS: Callback listener port = %u (af %u)\n", + nfs_callback_tcpport, PF_INET); + +- ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET6, ++ ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6, + nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); + if (ret > 0) { + nfs_callback_tcpport6 = ret; +@@ -183,7 +183,7 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) + * fore channel connection. + * Returns the input port (0) and sets the svc_serv bc_xprt on success + */ +- ret = svc_create_xprt(serv, "tcp-bc", xprt->xprt_net, PF_INET, 0, ++ ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0, + SVC_SOCK_ANONYMOUS); + if (ret < 0) { + rqstp = ERR_PTR(ret); +@@ -253,6 +253,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) + char svc_name[12]; + int ret = 0; + int minorversion_setup; ++ struct net *net = &init_net; + + mutex_lock(&nfs_callback_mutex); + if (cb_info->users++ || cb_info->task != NULL) { +@@ -265,6 +266,12 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) + goto out_err; + } + ++ ret = svc_bind(serv, net); ++ if (ret < 0) { ++ printk(KERN_WARNING "NFS: bind callback service failed\n"); ++ goto out_err; ++ } ++ + minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, + serv, xprt, &rqstp, &callback_svc); + if (!minorversion_setup) { +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 28dfad3..a6461f3 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -330,6 +331,8 @@ static int nfsd_get_default_max_blksize(void) + + int nfsd_create_serv(void) + { ++ int error; ++ + WARN_ON(!mutex_is_locked(&nfsd_mutex)); + if (nfsd_serv) { + svc_get(nfsd_serv); +@@ -343,6 +346,12 @@ int nfsd_create_serv(void) + if (nfsd_serv == NULL) + return -ENOMEM; + ++ error = svc_bind(nfsd_serv, current->nsproxy->net_ns); ++ if (error < 0) { ++ svc_destroy(nfsd_serv); ++ return error; ++ } ++ + set_max_drc(); + do_gettimeofday(&nfssvc_boot); /* record boot time */ + return 0; +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 51b29ac..2b43e02 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -416,6 +416,7 @@ struct svc_procedure { + */ + int svc_rpcb_setup(struct svc_serv *serv, struct net *net); + void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); ++int svc_bind(struct svc_serv *serv, struct net *net); + struct svc_serv *svc_create(struct svc_program *, unsigned int, + void (*shutdown)(struct svc_serv *, struct net *net)); + struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, +diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c +index 78ac39f..4c38b33 100644 +--- a/net/sunrpc/rpcb_clnt.c ++++ b/net/sunrpc/rpcb_clnt.c +@@ -180,14 +180,16 @@ void rpcb_put_local(struct net *net) + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct rpc_clnt *clnt = sn->rpcb_local_clnt; + struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; +- int shutdown; ++ int shutdown = 0; + + spin_lock(&sn->rpcb_clnt_lock); +- if (--sn->rpcb_users == 0) { +- sn->rpcb_local_clnt = NULL; +- sn->rpcb_local_clnt4 = NULL; ++ if (sn->rpcb_users) { ++ if (--sn->rpcb_users == 0) { ++ sn->rpcb_local_clnt = NULL; ++ sn->rpcb_local_clnt4 = NULL; ++ } ++ shutdown = !sn->rpcb_users; + } +- shutdown = !sn->rpcb_users; + spin_unlock(&sn->rpcb_clnt_lock); + + if (shutdown) { +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 4153846..e6d542c 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -407,6 +407,14 @@ static int svc_uses_rpcbind(struct svc_serv *serv) + return 0; + } + ++int svc_bind(struct svc_serv *serv, struct net *net) ++{ ++ if (!svc_uses_rpcbind(serv)) ++ return 0; ++ return svc_rpcb_setup(serv, net); ++} ++EXPORT_SYMBOL_GPL(svc_bind); ++ + /* + * Create an RPC service + */ +@@ -471,15 +479,8 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, + spin_lock_init(&pool->sp_lock); + } + +- if (svc_uses_rpcbind(serv)) { +- if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) { +- kfree(serv->sv_pools); +- kfree(serv); +- return NULL; +- } +- if (!serv->sv_shutdown) +- serv->sv_shutdown = svc_rpcb_cleanup; +- } ++ if (svc_uses_rpcbind(serv) && (!serv->sv_shutdown)) ++ serv->sv_shutdown = svc_rpcb_cleanup; + + return serv; + } + +-- +To unsubscribe from this list: send the line "unsubscribe linux-nfs" in +the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/add-poll-requested-events.patch b/add-poll-requested-events.patch deleted file mode 100644 index dafd359e1..000000000 --- a/add-poll-requested-events.patch +++ /dev/null @@ -1,393 +0,0 @@ -commit 626cf236608505d376e4799adb4f7eb00a8594af -Author: Hans Verkuil -Date: Fri Mar 23 15:02:27 2012 -0700 - - poll: add poll_requested_events() and poll_does_not_wait() functions - - In some cases the poll() implementation in a driver has to do different - things depending on the events the caller wants to poll for. An example - is when a driver needs to start a DMA engine if the caller polls for - POLLIN, but doesn't want to do that if POLLIN is not requested but instead - only POLLOUT or POLLPRI is requested. This is something that can happen - in the video4linux subsystem among others. - - Unfortunately, the current epoll/poll/select implementation doesn't - provide that information reliably. The poll_table_struct does have it: it - has a key field with the event mask. But once a poll() call matches one - or more bits of that mask any following poll() calls are passed a NULL - poll_table pointer. - - Also, the eventpoll implementation always left the key field at ~0 instead - of using the requested events mask. - - This was changed in eventpoll.c so the key field now contains the actual - events that should be polled for as set by the caller. - - The solution to the NULL poll_table pointer is to set the qproc field to - NULL in poll_table once poll() matches the events, not the poll_table - pointer itself. That way drivers can obtain the mask through a new - poll_requested_events inline. - - The poll_table_struct can still be NULL since some kernel code calls it - internally (netfs_state_poll() in ./drivers/staging/pohmelfs/netfs.h). In - that case poll_requested_events() returns ~0 (i.e. all events). - - Very rarely drivers might want to know whether poll_wait will actually - wait. If another earlier file descriptor in the set already matched the - events the caller wanted to wait for, then the kernel will return from the - select() call without waiting. This might be useful information in order - to avoid doing expensive work. - - A new helper function poll_does_not_wait() is added that drivers can use - to detect this situation. This is now used in sock_poll_wait() in - include/net/sock.h. This was the only place in the kernel that needed - this information. - - Drivers should no longer access any of the poll_table internals, but use - the poll_requested_events() and poll_does_not_wait() access functions - instead. In order to enforce that the poll_table fields are now prepended - with an underscore and a comment was added warning against using them - directly. - - This required a change in unix_dgram_poll() in unix/af_unix.c which used - the key field to get the requested events. It's been replaced by a call - to poll_requested_events(). - - For qproc it was especially important to change its name since the - behavior of that field changes with this patch since this function pointer - can now be NULL when that wasn't possible in the past. - - Any driver accessing the qproc or key fields directly will now fail to compile. - - Some notes regarding the correctness of this patch: the driver's poll() - function is called with a 'struct poll_table_struct *wait' argument. This - pointer may or may not be NULL, drivers can never rely on it being one or - the other as that depends on whether or not an earlier file descriptor in - the select()'s fdset matched the requested events. - - There are only three things a driver can do with the wait argument: - - 1) obtain the key field: - - events = wait ? wait->key : ~0; - - This will still work although it should be replaced with the new - poll_requested_events() function (which does exactly the same). - This will now even work better, since wait is no longer set to NULL - unnecessarily. - - 2) use the qproc callback. This could be deadly since qproc can now be - NULL. Renaming qproc should prevent this from happening. There are no - kernel drivers that actually access this callback directly, BTW. - - 3) test whether wait == NULL to determine whether poll would return without - waiting. This is no longer sufficient as the correct test is now - wait == NULL || wait->_qproc == NULL. - - However, the worst that can happen here is a slight performance hit in - the case where wait != NULL and wait->_qproc == NULL. In that case the - driver will assume that poll_wait() will actually add the fd to the set - of waiting file descriptors. Of course, poll_wait() will not do that - since it tests for wait->_qproc. This will not break anything, though. - - There is only one place in the whole kernel where this happens - (sock_poll_wait() in include/net/sock.h) and that code will be replaced - by a call to poll_does_not_wait() in the next patch. - - Note that even if wait->_qproc != NULL drivers cannot rely on poll_wait() - actually waiting. The next file descriptor from the set might match the - event mask and thus any possible waits will never happen. - - Signed-off-by: Hans Verkuil - Reviewed-by: Jonathan Corbet - Reviewed-by: Al Viro - Cc: Davide Libenzi - Signed-off-by: Hans de Goede - Cc: Mauro Carvalho Chehab - Cc: David Miller - Cc: Eric Dumazet - Signed-off-by: Andrew Morton - Signed-off-by: Linus Torvalds - -diff --git a/fs/eventpoll.c b/fs/eventpoll.c -index 4d9d3a4..ca30007 100644 ---- a/fs/eventpoll.c -+++ b/fs/eventpoll.c -@@ -699,9 +699,12 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, - void *priv) - { - struct epitem *epi, *tmp; -+ poll_table pt; - -+ init_poll_funcptr(&pt, NULL); - list_for_each_entry_safe(epi, tmp, head, rdllink) { -- if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) & -+ pt._key = epi->event.events; -+ if (epi->ffd.file->f_op->poll(epi->ffd.file, &pt) & - epi->event.events) - return POLLIN | POLLRDNORM; - else { -@@ -1097,6 +1100,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, - /* Initialize the poll table using the queue callback */ - epq.epi = epi; - init_poll_funcptr(&epq.pt, ep_ptable_queue_proc); -+ epq.pt._key = event->events; - - /* - * Attach the item to the poll hooks and get current event bits. -@@ -1191,6 +1195,9 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even - { - int pwake = 0; - unsigned int revents; -+ poll_table pt; -+ -+ init_poll_funcptr(&pt, NULL); - - /* - * Set the new event interest mask before calling f_op->poll(); -@@ -1198,13 +1205,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even - * f_op->poll() call and the new event set registering. - */ - epi->event.events = event->events; -+ pt._key = event->events; - epi->event.data = event->data; /* protected by mtx */ - - /* - * Get current event bits. We can safely use the file* here because - * its usage count has been increased by the caller of this function. - */ -- revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL); -+ revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt); - - /* - * If the item is "hot" and it is not registered inside the ready -@@ -1239,6 +1247,9 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, - unsigned int revents; - struct epitem *epi; - struct epoll_event __user *uevent; -+ poll_table pt; -+ -+ init_poll_funcptr(&pt, NULL); - - /* - * We can loop without lock because we are passed a task private list. -@@ -1251,7 +1262,8 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, - - list_del_init(&epi->rdllink); - -- revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) & -+ pt._key = epi->event.events; -+ revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt) & - epi->event.events; - - /* -diff --git a/fs/select.c b/fs/select.c -index e782258..ecfd0b1 100644 ---- a/fs/select.c -+++ b/fs/select.c -@@ -223,7 +223,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, - get_file(filp); - entry->filp = filp; - entry->wait_address = wait_address; -- entry->key = p->key; -+ entry->key = p->_key; - init_waitqueue_func_entry(&entry->wait, pollwake); - entry->wait.private = pwq; - add_wait_queue(wait_address, &entry->wait); -@@ -386,13 +386,11 @@ get_max: - static inline void wait_key_set(poll_table *wait, unsigned long in, - unsigned long out, unsigned long bit) - { -- if (wait) { -- wait->key = POLLEX_SET; -- if (in & bit) -- wait->key |= POLLIN_SET; -- if (out & bit) -- wait->key |= POLLOUT_SET; -- } -+ wait->_key = POLLEX_SET; -+ if (in & bit) -+ wait->_key |= POLLIN_SET; -+ if (out & bit) -+ wait->_key |= POLLOUT_SET; - } - - int do_select(int n, fd_set_bits *fds, struct timespec *end_time) -@@ -414,7 +412,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) - poll_initwait(&table); - wait = &table.pt; - if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { -- wait = NULL; -+ wait->_qproc = NULL; - timed_out = 1; - } - -@@ -459,17 +457,17 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) - if ((mask & POLLIN_SET) && (in & bit)) { - res_in |= bit; - retval++; -- wait = NULL; -+ wait->_qproc = NULL; - } - if ((mask & POLLOUT_SET) && (out & bit)) { - res_out |= bit; - retval++; -- wait = NULL; -+ wait->_qproc = NULL; - } - if ((mask & POLLEX_SET) && (ex & bit)) { - res_ex |= bit; - retval++; -- wait = NULL; -+ wait->_qproc = NULL; - } - } - } -@@ -481,7 +479,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) - *rexp = res_ex; - cond_resched(); - } -- wait = NULL; -+ wait->_qproc = NULL; - if (retval || timed_out || signal_pending(current)) - break; - if (table.error) { -@@ -720,7 +718,7 @@ struct poll_list { - * interested in events matching the pollfd->events mask, and the result - * matching that mask is both recorded in pollfd->revents and returned. The - * pwait poll_table will be used by the fd-provided poll handler for waiting, -- * if non-NULL. -+ * if pwait->_qproc is non-NULL. - */ - static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) - { -@@ -738,9 +736,7 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) - if (file != NULL) { - mask = DEFAULT_POLLMASK; - if (file->f_op && file->f_op->poll) { -- if (pwait) -- pwait->key = pollfd->events | -- POLLERR | POLLHUP; -+ pwait->_key = pollfd->events|POLLERR|POLLHUP; - mask = file->f_op->poll(file, pwait); - } - /* Mask out unneeded events. */ -@@ -763,7 +759,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list, - - /* Optimise the no-wait case */ - if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { -- pt = NULL; -+ pt->_qproc = NULL; - timed_out = 1; - } - -@@ -781,22 +777,22 @@ static int do_poll(unsigned int nfds, struct poll_list *list, - for (; pfd != pfd_end; pfd++) { - /* - * Fish for events. If we found one, record it -- * and kill the poll_table, so we don't -+ * and kill poll_table->_qproc, so we don't - * needlessly register any other waiters after - * this. They'll get immediately deregistered - * when we break out and return. - */ - if (do_pollfd(pfd, pt)) { - count++; -- pt = NULL; -+ pt->_qproc = NULL; - } - } - } - /* - * All waiters have already been registered, so don't provide -- * a poll_table to them on the next loop iteration. -+ * a poll_table->_qproc to them on the next loop iteration. - */ -- pt = NULL; -+ pt->_qproc = NULL; - if (!count) { - count = wait->error; - if (signal_pending(current)) -diff --git a/include/linux/poll.h b/include/linux/poll.h -index cf40010..48fe8bc 100644 ---- a/include/linux/poll.h -+++ b/include/linux/poll.h -@@ -32,21 +32,46 @@ struct poll_table_struct; - */ - typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); - -+/* -+ * Do not touch the structure directly, use the access functions -+ * poll_does_not_wait() and poll_requested_events() instead. -+ */ - typedef struct poll_table_struct { -- poll_queue_proc qproc; -- unsigned long key; -+ poll_queue_proc _qproc; -+ unsigned long _key; - } poll_table; - - static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p) - { -- if (p && wait_address) -- p->qproc(filp, wait_address, p); -+ if (p && p->_qproc && wait_address) -+ p->_qproc(filp, wait_address, p); -+} -+ -+/* -+ * Return true if it is guaranteed that poll will not wait. This is the case -+ * if the poll() of another file descriptor in the set got an event, so there -+ * is no need for waiting. -+ */ -+static inline bool poll_does_not_wait(const poll_table *p) -+{ -+ return p == NULL || p->_qproc == NULL; -+} -+ -+/* -+ * Return the set of events that the application wants to poll for. -+ * This is useful for drivers that need to know whether a DMA transfer has -+ * to be started implicitly on poll(). You typically only want to do that -+ * if the application is actually polling for POLLIN and/or POLLOUT. -+ */ -+static inline unsigned long poll_requested_events(const poll_table *p) -+{ -+ return p ? p->_key : ~0UL; - } - - static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc) - { -- pt->qproc = qproc; -- pt->key = ~0UL; /* all events enabled */ -+ pt->_qproc = qproc; -+ pt->_key = ~0UL; /* all events enabled */ - } - - struct poll_table_entry { -diff --git a/include/net/sock.h b/include/net/sock.h -index 04bc0b3..a6ba1f8 100644 ---- a/include/net/sock.h -+++ b/include/net/sock.h -@@ -1854,7 +1854,7 @@ static inline bool wq_has_sleeper(struct socket_wq *wq) - static inline void sock_poll_wait(struct file *filp, - wait_queue_head_t *wait_address, poll_table *p) - { -- if (p && wait_address) { -+ if (!poll_does_not_wait(p) && wait_address) { - poll_wait(filp, wait_address, p); - /* - * We need to be sure we are in sync with the -diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c -index eb4277c..d510353 100644 ---- a/net/unix/af_unix.c -+++ b/net/unix/af_unix.c -@@ -2206,7 +2206,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, - } - - /* No write status requested, avoid expensive OUT tests. */ -- if (wait && !(wait->key & (POLLWRBAND | POLLWRNORM | POLLOUT))) -+ if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT))) - return mask; - - writable = unix_writable(sk); diff --git a/atl1c_net_next_update-3.3.patch b/atl1c_net_next_update-3.4.patch similarity index 97% rename from atl1c_net_next_update-3.3.patch rename to atl1c_net_next_update-3.4.patch index 6c53ed607..1ec9771bc 100644 --- a/atl1c_net_next_update-3.3.patch +++ b/atl1c_net_next_update-3.4.patch @@ -178,7 +178,7 @@ index 0a9326a..859ea84 100644 static int atl1c_get_eeprom_len(struct net_device *netdev) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c -index 23f2ab0..2ea6a21 100644 +index bd1667c..ff9c738 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c @@ -43,7 +43,7 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw) @@ -376,14 +376,14 @@ index 23f2ab0..2ea6a21 100644 + AT_WRITE_REG(hw, REG_MDIO_CTRL, 0); + atl1c_wait_mdio_idle(hw); +} - ++ +void atl1c_start_phy_polling(struct atl1c_hw *hw, u16 clk_sel) +{ + u32 val; + + if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION)) + return; -+ + + val = MDIO_CTRL_SPRES_PRMBL | + FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) | + FIELDX(MDIO_CTRL_REG, 1) | @@ -2024,7 +2024,7 @@ index 655fc6c..17d935b 100644 #endif /*_ATL1C_HW_H_*/ diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c -index 47a9bb2..f6f3fe3 100644 +index 1ef0c92..9cc1570 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -24,14 +24,6 @@ @@ -2282,16 +2282,16 @@ index 47a9bb2..f6f3fe3 100644 } -@@ -469,7 +474,7 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p) - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); +@@ -470,7 +475,7 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p) memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); + netdev->addr_assign_type &= ~NET_ADDR_RANDOM; - atl1c_hw_set_mac_addr(&adapter->hw); + atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr); return 0; } -@@ -522,11 +527,16 @@ static int atl1c_set_features(struct net_device *netdev, +@@ -523,11 +528,16 @@ static int atl1c_set_features(struct net_device *netdev, static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) { struct atl1c_adapter *adapter = netdev_priv(netdev); @@ -2310,7 +2310,7 @@ index 47a9bb2..f6f3fe3 100644 if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, "invalid MTU setting\n"); return -EINVAL; -@@ -542,14 +552,6 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) +@@ -543,14 +553,6 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) netdev_update_features(netdev); atl1c_up(adapter); clear_bit(__AT_RESETTING, &adapter->flags); @@ -2325,7 +2325,7 @@ index 47a9bb2..f6f3fe3 100644 } return 0; } -@@ -562,7 +564,7 @@ static int atl1c_mdio_read(struct net_device *netdev, int phy_id, int reg_num) +@@ -563,7 +565,7 @@ static int atl1c_mdio_read(struct net_device *netdev, int phy_id, int reg_num) struct atl1c_adapter *adapter = netdev_priv(netdev); u16 result; @@ -2334,7 +2334,7 @@ index 47a9bb2..f6f3fe3 100644 return result; } -@@ -571,7 +573,7 @@ static void atl1c_mdio_write(struct net_device *netdev, int phy_id, +@@ -572,7 +574,7 @@ static void atl1c_mdio_write(struct net_device *netdev, int phy_id, { struct atl1c_adapter *adapter = netdev_priv(netdev); @@ -2343,7 +2343,7 @@ index 47a9bb2..f6f3fe3 100644 } /* -@@ -686,21 +688,15 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw) +@@ -687,21 +689,15 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw) static int atl1c_setup_mac_funcs(struct atl1c_hw *hw) { @@ -2367,7 +2367,7 @@ index 47a9bb2..f6f3fe3 100644 hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON; if (hw->nic_type == athr_l1c || -@@ -709,6 +705,55 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw) +@@ -710,6 +706,55 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw) hw->link_cap_flags |= ATL1C_LINK_CAP_1000M; return 0; } @@ -2423,7 +2423,7 @@ index 47a9bb2..f6f3fe3 100644 /* * atl1c_sw_init - Initialize general software structures (struct atl1c_adapter) * @adapter: board private structure to initialize -@@ -728,9 +773,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) +@@ -729,9 +774,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) device_set_wakeup_enable(&pdev->dev, false); adapter->link_speed = SPEED_0; adapter->link_duplex = FULL_DUPLEX; @@ -2434,7 +2434,7 @@ index 47a9bb2..f6f3fe3 100644 hw->vendor_id = pdev->vendor; hw->device_id = pdev->device; -@@ -745,26 +789,18 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) +@@ -746,26 +790,18 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) dev_err(&pdev->dev, "set mac function pointers failed\n"); return -1; } @@ -2463,7 +2463,7 @@ index 47a9bb2..f6f3fe3 100644 hw->rx_imt = 200; hw->tx_imt = 1000; -@@ -772,9 +808,6 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) +@@ -773,9 +809,6 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) hw->rfd_burst = 8; hw->dma_order = atl1c_dma_ord_out; hw->dmar_block = atl1c_dma_req_1024; @@ -2473,7 +2473,7 @@ index 47a9bb2..f6f3fe3 100644 if (atl1c_alloc_queues(adapter)) { dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); -@@ -850,24 +883,22 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter, +@@ -851,24 +884,22 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter, */ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter) { @@ -2510,7 +2510,7 @@ index 47a9bb2..f6f3fe3 100644 } /* -@@ -876,8 +907,8 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter) +@@ -877,8 +908,8 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter) static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter) { struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring; @@ -2521,7 +2521,7 @@ index 47a9bb2..f6f3fe3 100644 struct atl1c_buffer *buffer_info; int i, j; -@@ -889,15 +920,13 @@ static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter) +@@ -890,15 +921,13 @@ static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter) ATL1C_SET_BUFFER_STATE(&buffer_info[i], ATL1C_BUFFER_FREE); } @@ -2544,7 +2544,7 @@ index 47a9bb2..f6f3fe3 100644 } } -@@ -934,27 +963,23 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) +@@ -935,27 +964,23 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring; @@ -2576,7 +2576,7 @@ index 47a9bb2..f6f3fe3 100644 tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL); if (unlikely(!tpd_ring->buffer_info)) { dev_err(&pdev->dev, "kzalloc failed, size = %d\n", -@@ -967,12 +992,11 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) +@@ -968,12 +993,11 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) count += tpd_ring[i].count; } @@ -2594,7 +2594,7 @@ index 47a9bb2..f6f3fe3 100644 /* * real ring DMA buffer * each ring/block may need up to 8 bytes for alignment, hence the -@@ -982,8 +1006,7 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) +@@ -983,8 +1007,7 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) sizeof(struct atl1c_tpd_desc) * tpd_ring->count * 2 + sizeof(struct atl1c_rx_free_desc) * rx_desc_count + sizeof(struct atl1c_recv_ret_status) * rx_desc_count + @@ -2604,7 +2604,7 @@ index 47a9bb2..f6f3fe3 100644 ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, &ring_header->dma); -@@ -1004,25 +1027,18 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) +@@ -1005,25 +1028,18 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) offset += roundup(tpd_ring[i].size, 8); } /* init RFD ring */ @@ -2639,7 +2639,7 @@ index 47a9bb2..f6f3fe3 100644 return 0; err_nomem: -@@ -1033,26 +1049,20 @@ err_nomem: +@@ -1034,26 +1050,20 @@ err_nomem: static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) { struct atl1c_hw *hw = &adapter->hw; @@ -2670,7 +2670,7 @@ index 47a9bb2..f6f3fe3 100644 (u32)(tpd_ring[atl1c_trans_high].dma & AT_DMA_LO_ADDR_MASK)); AT_WRITE_REG(hw, REG_TPD_RING_SIZE, -@@ -1061,31 +1071,21 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) +@@ -1062,31 +1072,21 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) /* RFD */ AT_WRITE_REG(hw, REG_RX_BASE_ADDR_HI, @@ -2709,7 +2709,7 @@ index 47a9bb2..f6f3fe3 100644 if (hw->nic_type == athr_l2c_b) { AT_WRITE_REG(hw, REG_SRAM_RXF_LEN, 0x02a0L); AT_WRITE_REG(hw, REG_SRAM_TXF_LEN, 0x0100L); -@@ -1096,13 +1096,6 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) +@@ -1097,13 +1097,6 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) AT_WRITE_REG(hw, REG_TXF_WATER_MARK, 0); /* TX watermark, to enter l1 state.*/ AT_WRITE_REG(hw, REG_RXD_DMA_CTRL, 0); /* RXD threshold.*/ } @@ -2723,7 +2723,7 @@ index 47a9bb2..f6f3fe3 100644 /* Load all of base address above */ AT_WRITE_REG(hw, REG_LOAD_PTR, 1); } -@@ -1110,32 +1103,26 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) +@@ -1111,32 +1104,26 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter) static void atl1c_configure_tx(struct atl1c_adapter *adapter) { struct atl1c_hw *hw = &adapter->hw; @@ -2770,7 +2770,7 @@ index 47a9bb2..f6f3fe3 100644 AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data); } -@@ -1150,34 +1137,13 @@ static void atl1c_configure_rx(struct atl1c_adapter *adapter) +@@ -1151,34 +1138,13 @@ static void atl1c_configure_rx(struct atl1c_adapter *adapter) if (hw->ctrl_flags & ATL1C_RX_IPV6_CHKSUM) rxq_ctrl_data |= IPV6_CHKSUM_CTRL_EN; @@ -2810,7 +2810,7 @@ index 47a9bb2..f6f3fe3 100644 } static void atl1c_configure_dma(struct atl1c_adapter *adapter) -@@ -1185,36 +1151,11 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter) +@@ -1186,36 +1152,11 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter) struct atl1c_hw *hw = &adapter->hw; u32 dma_ctrl_data; @@ -2852,7 +2852,7 @@ index 47a9bb2..f6f3fe3 100644 AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data); } -@@ -1229,52 +1170,53 @@ static int atl1c_stop_mac(struct atl1c_hw *hw) +@@ -1230,52 +1171,53 @@ static int atl1c_stop_mac(struct atl1c_hw *hw) u32 data; AT_READ_REG(hw, REG_RXQ_CTRL, &data); @@ -2874,13 +2874,10 @@ index 47a9bb2..f6f3fe3 100644 AT_WRITE_REG(hw, REG_MAC_CTRL, data); - return (int)atl1c_wait_until_idle(hw); -+ return (int)atl1c_wait_until_idle(hw, -+ IDLE_STATUS_TXMAC_BUSY | IDLE_STATUS_RXMAC_BUSY); - } - +-} +- -static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw) -+static void atl1c_start_mac(struct atl1c_adapter *adapter) - { +-{ - u32 data; - - AT_READ_REG(hw, REG_RXQ_CTRL, &data); @@ -2899,10 +2896,13 @@ index 47a9bb2..f6f3fe3 100644 - } - data |= RXQ_CTRL_EN; - AT_WRITE_REG(hw, REG_RXQ_CTRL, data); --} -- ++ return (int)atl1c_wait_until_idle(hw, ++ IDLE_STATUS_TXMAC_BUSY | IDLE_STATUS_RXMAC_BUSY); + } + -static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw) --{ ++static void atl1c_start_mac(struct atl1c_adapter *adapter) + { - u32 data; + struct atl1c_hw *hw = &adapter->hw; + u32 mac, txq, rxq; @@ -2938,7 +2938,7 @@ index 47a9bb2..f6f3fe3 100644 } /* -@@ -1286,10 +1228,7 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) +@@ -1287,10 +1229,7 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) { struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; struct pci_dev *pdev = adapter->pdev; @@ -2950,7 +2950,7 @@ index 47a9bb2..f6f3fe3 100644 atl1c_stop_mac(hw); /* -@@ -1298,194 +1237,148 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) +@@ -1299,194 +1238,148 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) * the current PCI configuration. The global reset bit is self- * clearing, and should clear within a microsecond. */ @@ -3238,7 +3238,7 @@ index 47a9bb2..f6f3fe3 100644 /* clear interrupt status */ AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF); /* Clear any WOL status */ -@@ -1524,30 +1417,39 @@ static int atl1c_configure(struct atl1c_adapter *adapter) +@@ -1525,30 +1418,39 @@ static int atl1c_configure(struct atl1c_adapter *adapter) master_ctrl_data |= MASTER_CTRL_SA_TIMER_EN; AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data); @@ -3290,7 +3290,7 @@ index 47a9bb2..f6f3fe3 100644 static void atl1c_update_hw_stats(struct atl1c_adapter *adapter) { u16 hw_reg_addr = 0; -@@ -1634,16 +1536,11 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter, +@@ -1635,16 +1537,11 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter, struct pci_dev *pdev = adapter->pdev; u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean); u16 hw_next_to_clean; @@ -3310,7 +3310,7 @@ index 47a9bb2..f6f3fe3 100644 while (next_to_clean != hw_next_to_clean) { buffer_info = &tpd_ring->buffer_info[next_to_clean]; -@@ -1745,9 +1642,9 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter, +@@ -1746,9 +1643,9 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter, skb_checksum_none_assert(skb); } @@ -3322,7 +3322,7 @@ index 47a9bb2..f6f3fe3 100644 struct pci_dev *pdev = adapter->pdev; struct atl1c_buffer *buffer_info, *next_info; struct sk_buff *skb; -@@ -1799,7 +1696,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid +@@ -1800,7 +1697,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid /* TODO: update mailbox here */ wmb(); rfd_ring->next_to_use = rfd_next_to_use; @@ -3331,7 +3331,7 @@ index 47a9bb2..f6f3fe3 100644 rfd_ring->next_to_use & MB_RFDX_PROD_IDX_MASK); } -@@ -1838,7 +1735,7 @@ static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring, +@@ -1839,7 +1736,7 @@ static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring, rfd_ring->next_to_clean = rfd_index; } @@ -3340,7 +3340,7 @@ index 47a9bb2..f6f3fe3 100644 int *work_done, int work_to_do) { u16 rfd_num, rfd_index; -@@ -1846,8 +1743,8 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, +@@ -1847,8 +1744,8 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, u16 length; struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; @@ -3351,7 +3351,7 @@ index 47a9bb2..f6f3fe3 100644 struct sk_buff *skb; struct atl1c_recv_ret_status *rrs; struct atl1c_buffer *buffer_info; -@@ -1913,7 +1810,7 @@ rrs_checked: +@@ -1914,7 +1811,7 @@ rrs_checked: count++; } if (count) @@ -3360,7 +3360,7 @@ index 47a9bb2..f6f3fe3 100644 } /* -@@ -1930,7 +1827,7 @@ static int atl1c_clean(struct napi_struct *napi, int budget) +@@ -1931,7 +1828,7 @@ static int atl1c_clean(struct napi_struct *napi, int budget) if (!netif_carrier_ok(adapter->netdev)) goto quit_polling; /* just enable one RXQ */ @@ -3369,7 +3369,7 @@ index 47a9bb2..f6f3fe3 100644 if (work_done < budget) { quit_polling: -@@ -2205,23 +2102,10 @@ static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, +@@ -2206,23 +2103,10 @@ static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb, struct atl1c_tpd_desc *tpd, enum atl1c_trans_queue type) { struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type]; @@ -3396,7 +3396,17 @@ index 47a9bb2..f6f3fe3 100644 } static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, -@@ -2327,44 +2211,38 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter) +@@ -2307,8 +2191,7 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter) + "Unable to allocate MSI interrupt Error: %d\n", + err); + adapter->have_msi = false; +- } else +- netdev->irq = pdev->irq; ++ } + + if (!adapter->have_msi) + flags |= IRQF_SHARED; +@@ -2328,44 +2211,38 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter) return err; } @@ -3420,7 +3430,7 @@ index 47a9bb2..f6f3fe3 100644 - atl1c_init_ring_ptrs(adapter); - atl1c_set_multi(netdev); - atl1c_restore_vlan(adapter); -- + - for (i = 0; i < adapter->num_rx_queues; i++) { - num = atl1c_alloc_rx_buffer(adapter, i); - if (unlikely(num == 0)) { @@ -3428,7 +3438,7 @@ index 47a9bb2..f6f3fe3 100644 - goto err_alloc_rx; - } - } - +- - if (atl1c_configure(adapter)) { - err = -EIO; + err = atl1c_configure(adapter); @@ -3453,7 +3463,7 @@ index 47a9bb2..f6f3fe3 100644 atl1c_clean_rx_ring(adapter); return err; } -@@ -2382,15 +2260,15 @@ static void atl1c_down(struct atl1c_adapter *adapter) +@@ -2383,15 +2260,15 @@ static void atl1c_down(struct atl1c_adapter *adapter) napi_disable(&adapter->napi); atl1c_irq_disable(adapter); atl1c_free_irq(adapter); @@ -3472,7 +3482,7 @@ index 47a9bb2..f6f3fe3 100644 } /* -@@ -2423,13 +2301,6 @@ static int atl1c_open(struct net_device *netdev) +@@ -2424,13 +2301,6 @@ static int atl1c_open(struct net_device *netdev) if (unlikely(err)) goto err_up; @@ -3486,7 +3496,7 @@ index 47a9bb2..f6f3fe3 100644 return 0; err_up: -@@ -2455,6 +2326,8 @@ static int atl1c_close(struct net_device *netdev) +@@ -2456,6 +2326,8 @@ static int atl1c_close(struct net_device *netdev) struct atl1c_adapter *adapter = netdev_priv(netdev); WARN_ON(test_bit(__AT_RESETTING, &adapter->flags)); @@ -3495,7 +3505,7 @@ index 47a9bb2..f6f3fe3 100644 atl1c_down(adapter); atl1c_free_ring_resources(adapter); return 0; -@@ -2466,10 +2339,6 @@ static int atl1c_suspend(struct device *dev) +@@ -2467,10 +2339,6 @@ static int atl1c_suspend(struct device *dev) struct net_device *netdev = pci_get_drvdata(pdev); struct atl1c_adapter *adapter = netdev_priv(netdev); struct atl1c_hw *hw = &adapter->hw; @@ -3506,7 +3516,7 @@ index 47a9bb2..f6f3fe3 100644 u32 wufc = adapter->wol; atl1c_disable_l0s_l1(hw); -@@ -2480,75 +2349,10 @@ static int atl1c_suspend(struct device *dev) +@@ -2481,75 +2349,10 @@ static int atl1c_suspend(struct device *dev) netif_device_detach(netdev); if (wufc) @@ -3584,7 +3594,7 @@ index 47a9bb2..f6f3fe3 100644 return 0; } -@@ -2561,8 +2365,7 @@ static int atl1c_resume(struct device *dev) +@@ -2562,8 +2365,7 @@ static int atl1c_resume(struct device *dev) struct atl1c_adapter *adapter = netdev_priv(netdev); AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); @@ -3594,7 +3604,22 @@ index 47a9bb2..f6f3fe3 100644 atl1c_phy_reset(&adapter->hw); atl1c_reset_mac(&adapter->hw); -@@ -2713,7 +2516,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, +@@ -2616,7 +2418,6 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev) + SET_NETDEV_DEV(netdev, &pdev->dev); + pci_set_drvdata(pdev, netdev); + +- netdev->irq = pdev->irq; + netdev->netdev_ops = &atl1c_netdev_ops; + netdev->watchdog_timeo = AT_TX_WATCHDOG; + atl1c_set_ethtool_ops(netdev); +@@ -2706,14 +2507,13 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, + dev_err(&pdev->dev, "cannot map device registers\n"); + goto err_ioremap; + } +- netdev->base_addr = (unsigned long)adapter->hw.hw_addr; + + /* init mii data */ + adapter->mii.dev = netdev; adapter->mii.mdio_read = atl1c_mdio_read; adapter->mii.mdio_write = atl1c_mdio_write; adapter->mii.phy_id_mask = 0x1f; @@ -3603,7 +3628,7 @@ index 47a9bb2..f6f3fe3 100644 netif_napi_add(netdev, &adapter->napi, atl1c_clean, 64); setup_timer(&adapter->phy_config_timer, atl1c_phy_config, (unsigned long)adapter); -@@ -2723,8 +2526,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, +@@ -2723,8 +2523,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "net device private data init failed\n"); goto err_sw_init; } @@ -3613,7 +3638,7 @@ index 47a9bb2..f6f3fe3 100644 /* Init GPHY as early as possible due to power saving issue */ atl1c_phy_reset(&adapter->hw); -@@ -2753,7 +2555,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, +@@ -2752,7 +2551,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, dev_dbg(&pdev->dev, "mac address : %pM\n", adapter->hw.mac_addr); @@ -3622,7 +3647,7 @@ index 47a9bb2..f6f3fe3 100644 INIT_WORK(&adapter->common_task, atl1c_common_task); adapter->work_event = 0; err = register_netdev(netdev); -@@ -2798,6 +2600,8 @@ static void __devexit atl1c_remove(struct pci_dev *pdev) +@@ -2796,6 +2595,8 @@ static void __devexit atl1c_remove(struct pci_dev *pdev) struct atl1c_adapter *adapter = netdev_priv(netdev); unregister_netdev(netdev); diff --git a/bluetooth-use-after-free.patch b/bluetooth-use-after-free.patch deleted file mode 100644 index 0d21cad9a..000000000 --- a/bluetooth-use-after-free.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 2a5a5ec620a29d4ba07743c3151cdf0a417c8f8c Mon Sep 17 00:00:00 2001 -From: Andrei Emeltchenko -Date: Thu, 2 Feb 2012 10:32:18 +0200 -Subject: [PATCH] Bluetooth: Use list _safe deleting from conn chan_list - -Fixes possible bug when deleting element from the list in -function hci_chan_list_flush. list_for_each_entry_rcu is used -and after deleting element from the list we also free pointer -and then list_entry_rcu is taken from freed pointer. - -Signed-off-by: Andrei Emeltchenko -Acked-by: Marcel Holtmann -Signed-off-by: Johan Hedberg ---- - net/bluetooth/hci_conn.c | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c -index b074bd6..b4ecdde 100644 ---- a/net/bluetooth/hci_conn.c -+++ b/net/bluetooth/hci_conn.c -@@ -975,10 +975,10 @@ int hci_chan_del(struct hci_chan *chan) - - void hci_chan_list_flush(struct hci_conn *conn) - { -- struct hci_chan *chan; -+ struct hci_chan *chan, *n; - - BT_DBG("conn %p", conn); - -- list_for_each_entry_rcu(chan, &conn->chan_list, list) -+ list_for_each_entry_safe(chan, n, &conn->chan_list, list) - hci_chan_del(chan); - } --- -1.7.6.5 - -From 3c4e0df028935618d052235ba85bc7079be13394 Mon Sep 17 00:00:00 2001 -From: Andrei Emeltchenko -Date: Thu, 2 Feb 2012 10:32:17 +0200 -Subject: [PATCH] Bluetooth: Use list _safe deleting from conn_hash_list - -Use list_for_each_entry_safe which is safe version against removal -of list entry. Otherwise we remove hci_conn element and reference -next element which result in accessing LIST_POISON. - -[ 95.571834] Bluetooth: unknown link type 127 -[ 95.578349] BUG: unable to handle kernel paging request at 20002000 -[ 95.580236] IP: [<20002000>] 0x20001fff -[ 95.580763] *pde = 00000000 -[ 95.581196] Oops: 0000 [#1] SMP -... -[ 95.582298] Pid: 3355, comm: hciconfig Tainted: G O 3.2.0-VirttualBox -[ 95.582298] EIP: 0060:[<20002000>] EFLAGS: 00210206 CPU: 0 -[ 95.582298] EIP is at 0x20002000 -... -[ 95.582298] Call Trace: -[ 95.582298] [] ? hci_conn_hash_flush+0x76/0xf0 [bluetooth] -[ 95.582298] [] hci_dev_do_close+0xc1/0x2e0 [bluetooth] -[ 95.582298] [] ? hci_dev_get+0x69/0xb0 [bluetooth] -[ 95.582298] [] hci_dev_close+0x2a/0x50 [bluetooth] -[ 95.582298] [] hci_sock_ioctl+0x1af/0x3f0 [bluetooth] -[ 95.582298] [] ? handle_pte_fault+0x8a/0x8f0 -[ 95.582298] [] sock_ioctl+0x5f/0x260 -[ 95.582298] [] ? sock_fasync+0x90/0x90 -[ 95.582298] [] do_vfs_ioctl+0x83/0x5b0 -[ 95.582298] [] ? do_page_fault+0x297/0x500 -[ 95.582298] [] ? spurious_fault+0xd0/0xd0 -[ 95.582298] [] ? up_read+0x1b/0x30 -[ 95.582298] [] ? do_page_fault+0x297/0x500 -[ 95.582298] [] ? init_fpu+0xef/0x160 -[ 95.582298] [] ? do_debug+0x180/0x180 -[ 95.582298] [] ? fpu_finit+0x28/0x80 -[ 95.582298] [] sys_ioctl+0x87/0x90 -[ 95.582298] [] sysenter_do_call+0x12/0x38 -... - -Signed-off-by: Andrei Emeltchenko -Acked-by: Marcel Holtmann -Signed-off-by: Johan Hedberg ---- - net/bluetooth/hci_conn.c | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c -index aca71c0..b074bd6 100644 ---- a/net/bluetooth/hci_conn.c -+++ b/net/bluetooth/hci_conn.c -@@ -795,11 +795,11 @@ timer: - void hci_conn_hash_flush(struct hci_dev *hdev) - { - struct hci_conn_hash *h = &hdev->conn_hash; -- struct hci_conn *c; -+ struct hci_conn *c, *n; - - BT_DBG("hdev %s", hdev->name); - -- list_for_each_entry_rcu(c, &h->list, list) { -+ list_for_each_entry_safe(c, n, &h->list, list) { - c->state = BT_CLOSED; - - hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); --- -1.7.6.5 - diff --git a/config-arm-generic b/config-arm-generic index 6cb515ddb..80a7f2b87 100644 --- a/config-arm-generic +++ b/config-arm-generic @@ -1,15 +1,35 @@ CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y -# CONFIG_SMP is not set +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y # CONFIG_CMDLINE_FORCE is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_ARCH_VERSATILE=y -CONFIG_ARCH_VERSATILE_PB=y -CONFIG_MACH_VERSATILE_AB=y -CONFIG_MACH_VERSATILE_DT=y +CONFIG_ARCH_VEXPRESS=y +CONFIG_ARCH_VEXPRESS_CA9X4=y +CONFIG_ARCH_VEXPRESS_DT=y +CONFIG_PLAT_VERSATILE_CLCD=y +CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y +CONFIG_PLAT_VERSATILE=y +CONFIG_ARM_TIMER_SP804=y + +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y CONFIG_HIGHMEM=y # CONFIG_HIGHPTE is not set @@ -26,9 +46,18 @@ CONFIG_ZBOOT_ROM_BSS=0 CONFIG_ATAGS_PROC=y +CONFIG_CPU_IDLE=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +ONFIG_CPU_IDLE_GOV_MENU=y + +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + # CONFIG_FPE_NWFPE is not set CONFIG_FPE_FASTFPE=y CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y CONFIG_PM=y # CONFIG_PM_DEBUG is not set @@ -42,15 +71,12 @@ CONFIG_ARM_THUMB=y CONFIG_AEABI=y CONFIG_OABI_COMPAT=y +CONFIG_HW_PERF_EVENTS=y + # CONFIG_UACCESS_WITH_MEMCPY is not set CONFIG_CMDLINE="console=ttyAM0,115200 root=/dev/sda1 rootdelay=20" -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y - -# CONFIG_CPU_IDLE is not set - CONFIG_LEDS=y CONFIG_LEDS_CPU=y @@ -94,16 +120,20 @@ CONFIG_USB_TUSB6010=y CONFIG_MMC_ARMMMCI=m CONFIG_MMC_DW=m +CONFIG_MMC_DW_PLTFM=y +# CONFIG_MMC_DW_PCI is not set # CONFIG_MMC_DW_IDMAC is not set -CONFIG_RTC_DRV_PL030=m -CONFIG_RTC_DRV_PL031=m +CONFIG_RTC_DRV_PL030=y +CONFIG_RTC_DRV_PL031=y # CONFIG_SGI_IOC4 is not set # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_ERRORS is not set # CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set CONFIG_ARM_UNWIND=y @@ -164,6 +194,36 @@ CONFIG_PL330_DMA=y CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 CONFIG_LSM_MMAP_MIN_ADDR=32768 +# CONFIG_ARM_LPAE is not set +# CONFIG_ARM_THUMBEE is not set +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CACHE_L2X0=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_PL310_ERRATA_769419 is not set +CONFIG_SCHED_MC=y +# CONFIG_SCHED_SMT is not set +CONFIG_LOCAL_TIMERS=y +# CONFIG_THUMB2_KERNEL is not set +# CONFIG_PATA_PLATFORM is not set +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_MPCORE_WATCHDOG is not set + +CONFIG_DVB_PLL=m +CONFIG_DVB_TDA1004X=m + # disable TPM on arm at least on the trimslices it causes havoc # CONFIG_TCG_TPM is not set # CONFIG_IMA is not set @@ -179,6 +239,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=32768 # CONFIG_DRM_RADEON is not set # CONFIG_ATM_HE is not set # CONFIG_SCSI_ACARD is not set +# CONFIG_SFC is not set # these all currently fail due to missing symbols __bad_udelay or # error: implicit declaration of function ‘iowrite32be’ @@ -186,24 +247,25 @@ CONFIG_LSM_MMAP_MIN_ADDR=32768 # CONFIG_DRM_NOUVEAU is not set # CONFIG_MLX4_EN is not set +# drivers/input/touchscreen/eeti_ts.c:65:2: error: implicit declaration of function 'irq_to_gpio' [-Werror=implicit-function-declaration] +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# # FIXME: Guesses, need checking # CONFIG_MACH_EUKREA_CPUIMX35SD is not set CONFIG_ARM_ERRATA_720789=y CONFIG_ARM_ERRATA_751472=y -<<<<<<< HEAD -======= CONFIG_ARM_ERRATA_326103=y -CONFIG_OMAP4_ERRATA_I688=y ->>>>>>> 99667a9... Linux 3.3.5 +# CONFIG_OMAP4_ERRATA_I688 is not set # CONFIG_FB_MX3 is not set # CONFIG_MX3_IPU is not set # CONFIG_MX3_IPU_IRQS is not set -# CONFIG_OF_SELFTEST is not set -# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set -# CONFIG_INPUT_GP2A is not set -# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_CS89x0 is not set +# CONFIG_OF_SELFTEST is not set # CONFIG_MACH_IMX51_DT is not set # CONFIG_MACH_IMX53_DT is not set # CONFIG_MACH_MX53_EVK is not set @@ -211,3 +273,93 @@ CONFIG_OMAP4_ERRATA_I688=y # CONFIG_MACH_MX53_LOCO is not set # CONFIG_MACH_MX53_ARD is not set # CONFIG_ARM_EXYNOS4210_CPUFREQ is not set + +CONFIG_OF_GPIO=y +CONFIG_INPUT_GP2A=m +CONFIG_INPUT_GPIO_TILT_POLLED=m + +CONFIG_BPF_JIT=y + +CONFIG_MTD=m +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_AFS_PARTS=y +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_CFI=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_CFI_UTIL=y +CONFIG_MTD_DOC2000=m +CONFIG_MTD_DOC2001=m +CONFIG_MTD_DOC2001PLUS=m +# CONFIG_MTD_DOCPROBE_ADVANCED is not set +CONFIG_MTD_ALAUDA=m +# CONFIG_MTD_ONENAND is not set +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set +# 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_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_PHYSMAP=m +# CONFIG_MTD_PHYSMAP_COMPAT is not set +CONFIG_MTD_M25P80=m +CONFIG_M25PXX_USE_FAST_READ=y +CONFIG_MTD_NAND=m +CONFIG_MTD_NAND_ECC=m +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_DOCG4 is not set +CONFIG_MTD_NAND_GPIO=m +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_NAND_NANDSIM is not set +CONFIG_MTD_NAND_ORION=m +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set +# CONFIG_MTD_UBI_DEBUG is not set + +# CONFIG_SM_FTL is not set + +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set + +CONFIG_UBIFS_FS=m +CONFIG_UBIFS_FS_XATTR=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set diff --git a/config-arm-highbank b/config-arm-highbank index 8cd7fc3b5..60178dd1f 100644 --- a/config-arm-highbank +++ b/config-arm-highbank @@ -1,17 +1,31 @@ -ONFIG_ARCH_HIGHBANK=y -CONFIG_VFP=y -CONFIG_NEON=y +CONFIG_ARCH_HIGHBANK=y +# CONFIG_ARM_LPAE is not set +# CONFIG_ARM_THUMBEE is not set +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_PL310_ERRATA_769419 is not set -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEBUG=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPU_FREQ_TABLE=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y +# CONFIG_THUMB2_KERNEL is not set + +CONFIG_ARM_TIMER_SP804=y + +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_ATA_SFF=y + +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y CONFIG_NET_CALXEDA_XGMAC=y + +CONFIG_GPIO_PL061=y + +CONFIG_SERIAL_AMBA_PL010=y +CONFIG_SERIAL_AMBA_PL010_CONSOLE=y + diff --git a/config-arm-imx b/config-arm-imx index 2dbe10a1f..493769814 100644 --- a/config-arm-imx +++ b/config-arm-imx @@ -3,8 +3,6 @@ CONFIG_ARCH_MX51=y CONFIG_MACH_MX51_BABBAGE=y CONFIG_MACH_MX51_3DS=y CONFIG_MACH_EUKREA_CPUIMX51=y -CONFIG_VFP=y -CONFIG_NEON=y CONFIG_MACH_EUKREA_CPUIMX51SD=y CONFIG_MACH_MX51_EFIKAMX=y @@ -13,6 +11,7 @@ CONFIG_MACH_MX51_EFIKASB=y # CONFIG_THUMB2_KERNEL is not set CONFIG_CPU_FREQ_IMX=y CONFIG_W1_MASTER_MXC=m +CONFIG_IMX_DMA=m CONFIG_IMX_SDMA=y CONFIG_MACH_MX31ADS=y CONFIG_MACH_MX31LILLY=y @@ -33,13 +32,12 @@ CONFIG_MXC_IRQ_PRIOR=y CONFIG_MXC_PWM=m CONFIG_MXC_DEBUG_BOARD=y # CONFIG_CPU_BPREDICT_DISABLE is not set -# CONFIG_CACHE_L2X0 is not set +CONFIG_CACHE_L2X0=y CONFIG_ARM_DMA_MEM_BUFFERABLE=y CONFIG_ARM_ERRATA_411920=y CONFIG_PL310_ERRATA_588369=y CONFIG_PL310_ERRATA_727915=y CONFIG_ARM_ERRATA_364296=y -CONFIG_HW_PERF_EVENTS=y CONFIG_RFKILL_GPIO=m CONFIG_PATA_IMX=m CONFIG_ETHERNET=y @@ -52,14 +50,13 @@ CONFIG_HW_RANDOM_MXC_RNGA=m CONFIG_I2C_IMX=m CONFIG_GPIO_GENERIC_PLATFORM=y CONFIG_GPIO_MCP23S08=m -CONFIG_DVB_TDA1004X=m -CONFIG_DVB_PLL=m +# CONFIG_GPIO_MC9S08DZ60 is not set CONFIG_SND_IMX_SOC=m CONFIG_USB_EHCI_MXC=y -CONFIG_USB_IMX21_HCD=m +# CONFIG_USB_IMX21_HCD is not set CONFIG_MMC_SDHCI_ESDHC_IMX=m CONFIG_MMC_MXC=m -CONFIG_RTC_MXC=m +CONFIG_RTC_MXC=y CONFIG_BACKLIGHT_PWM=m CONFIG_LEDS_PWM=m @@ -81,18 +78,12 @@ CONFIG_IMX2_WDT=m CONFIG_SND_SOC_PHYCORE_AC97=m CONFIG_SND_SOC_EUKREA_TLV320=m -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEBUG=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPU_FREQ_TABLE=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y - CONFIG_PL310_ERRATA_769419=y CONFIG_LEDS_RENESAS_TPU=y + +# CONFIG_ARM_LPAE is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set + +CONFIG_MFD_ANATOP=y + diff --git a/config-arm-kirkwood b/config-arm-kirkwood index 415e822dc..3d3466bc4 100644 --- a/config-arm-kirkwood +++ b/config-arm-kirkwood @@ -1,4 +1,7 @@ CONFIG_ARCH_KIRKWOOD=y +CONFIG_ARCH_KIRKWOOD_DT=y +# CONFIG_SMP is not set +# CONFIG_VFP is not set CONFIG_MACH_DB88F6281_BP=y CONFIG_MACH_RD88F6192_NAS=y CONFIG_MACH_RD88F6281=y @@ -6,6 +9,7 @@ CONFIG_MACH_MV88F6281GTW_GE=y CONFIG_MACH_SHEEVAPLUG=y CONFIG_MACH_ESATA_SHEEVAPLUG=y CONFIG_MACH_GURUPLUG=y +CONFIG_MACH_DREAMPLUG_DT=y CONFIG_MACH_DOCKSTAR=y CONFIG_MACH_TS219=y CONFIG_MACH_TS41X=y @@ -36,8 +40,15 @@ CONFIG_SND_KIRKWOOD_SOC_T5325=m CONFIG_MMC_MVSDIO=m CONFIG_LEDS_NS2=m CONFIG_LEDS_NETXBIG=m -CONFIG_RTC_DRV_MV=m +CONFIG_RTC_DRV_MV=y CONFIG_MV_XOR=y CONFIG_CRYPTO_DEV_MV_CESA=m -# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set + + +# CONFIG_VFP is not set +# CONFIG_VFPv3 is not set +# CONFIG_NEON is not set +# CONFIG_SMP is not set diff --git a/config-arm-omap-generic b/config-arm-omap-generic index de17513e4..c4f22dc3d 100644 --- a/config-arm-omap-generic +++ b/config-arm-omap-generic @@ -1,3 +1,5 @@ +# CONFIG_OMAP4_ERRATA_I688 is not set + CONFIG_GENERIC_GPIO=y CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y CONFIG_GENERIC_LOCKBREAK=y @@ -10,7 +12,6 @@ CONFIG_RCU_FANOUT=32 # CONFIG_RCU_BOOST is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -# CONFIG_BLK_CGROUP is not set # CONFIG_SCHED_AUTOGROUP is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -143,9 +144,7 @@ CONFIG_LOCAL_TIMERS=y CONFIG_PREEMPT=y CONFIG_HZ=128 # CONFIG_THUMB2_KERNEL is not set -# CONFIG_OABI_COMPAT is not set CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y -CONFIG_HW_PERF_EVENTS=y CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_KSM is not set # CONFIG_CC_STACKPROTECTOR is not set @@ -153,23 +152,6 @@ CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="" # CONFIG_AUTO_ZRELADDR is not set -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_TABLE=y -CONFIG_CPU_FREQ_DEBUG=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_GOV_LADDER=y -CONFIG_CPU_IDLE_GOV_MENU=y CONFIG_VFPv3=y CONFIG_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set @@ -242,6 +224,7 @@ CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND=y # CONFIG_MTD_SM_COMMON is not set # CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_DOCG4 is not set CONFIG_MTD_NAND_OMAP2=y CONFIG_MTD_NAND_OMAP_PREFETCH=y CONFIG_MTD_NAND_OMAP_PREFETCH_DMA=y @@ -377,6 +360,7 @@ CONFIG_TOUCHSCREEN_AD7879_I2C=m CONFIG_TOUCHSCREEN_CY8CTMG110=m CONFIG_TOUCHSCREEN_HAMPSHIRE=m CONFIG_TOUCHSCREEN_QT602240=m +CONFIG_TOUCHSCREEN_TI_TSCADC=m CONFIG_TOUCHSCREEN_TPS6507X=m # CONFIG_TOUCHSCREEN_TSC2005 is not set CONFIG_INPUT_AD714X=m @@ -386,6 +370,7 @@ CONFIG_INPUT_AD714X_SPI=m CONFIG_INPUT_TWL4030_PWRBUTTON=y CONFIG_INPUT_TWL4030_VIBRA=y CONFIG_INPUT_TWL6040_VIBRA=y +CONFIG_KEYBOARD_OMAP4=m CONFIG_INPUT_UINPUT=y # CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set CONFIG_INPUT_ADXL34X=m @@ -577,14 +562,17 @@ CONFIG_TWL4030_CORE=y CONFIG_TWL4030_POWER=y CONFIG_TWL4030_CODEC=y # CONFIG_TWL6030_PWM is not set +# CONFIG_TWL6040_CORE is not set # CONFIG_MFD_STMPE is not set # CONFIG_MFD_TC3589X is not set # CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TPS65090 is not set/ # CONFIG_PMIC_DA903X is not set # CONFIG_PMIC_ADP5520 is not set # CONFIG_MFD_MAX8925 is not set # CONFIG_MFD_MAX8997 is not set # CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_RC5T583 is not set # CONFIG_MFD_WM8400 is not set # CONFIG_MFD_WM831X_I2C is not set # CONFIG_MFD_WM831X_SPI is not set @@ -612,6 +600,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_TWL4030=y # CONFIG_REGULATOR_LP3971 is not set # CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS62360 is not set # CONFIG_REGULATOR_TPS65023 is not set # CONFIG_REGULATOR_TPS6507X is not set # CONFIG_REGULATOR_ISL6271A is not set @@ -679,9 +668,9 @@ CONFIG_RADIO_TEF6862=m # CONFIG_TTPCI_EEPROM is not set # CONFIG_SMS_SDIO_DRV is not set # CONFIG_DVB_DUMMY_FE is not set -CONFIG_DVB_TDA1004X=m -CONFIG_DVB_PLL=m -# CONFIG_DRM is not set +CONFIG_DRM=m +CONFIG_DRM_OMAP=m +CONFIG_DRM_OMAP_NUM_CRTCS=2 # CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set # CONFIG_FB_DDC is not set @@ -712,9 +701,7 @@ CONFIG_OMAP4_DSS_HDMI=y CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=1 CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET=y CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET=y -CONFIG_FB_OMAP2=y -CONFIG_FB_OMAP2_DEBUG_SUPPORT=y -CONFIG_FB_OMAP2_NUM_FBS=3 +# CONFIG_FB_OMAP2 is not set # # OMAP2/3 Display Device Drivers @@ -732,6 +719,7 @@ CONFIG_PANEL_TPO_TD043MTEA1=y # CONFIG_LCD_S6E63M0 is not set # CONFIG_LCD_AMS369FG06 is not set CONFIG_BACKLIGHT_GENERIC=m +# CONFIG_BACKLIGHT_PANDORA is not set CONFIG_DISPLAY_SUPPORT=y # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set CONFIG_LOGO_LINUX_MONO=y @@ -1050,7 +1038,6 @@ CONFIG_LIBCRC32C=y # CONFIG_LCD_LD9040 is not set # CONFIG_RTC_DRV_M41T93 is not set # CONFIG_EXT2_FS_XATTR is not set -# CONFIG_CGROUP_PERF is not set # CONFIG_OPROFILE is not set # CONFIG_OPROFILE is not set # CONFIG_PATA_ARASAN_CF is not set @@ -1058,8 +1045,6 @@ CONFIG_LIBCRC32C=y # CONFIG_BT_WILINK is not set # CONFIG_USB_HSO is not set -CONFIG_CRYSTALHD=m - CONFIG_GPIO_GENERIC_PLATFORM=y CONFIG_MACH_OMAP_GENERIC=y @@ -1083,14 +1068,19 @@ CONFIG_LEDS_RENESAS_TPU=y # CONFIG_OMAP_IOMMU is not set CONFIG_USB_RENESAS_USBHS_HCD=m +# CONFIG_ARM_LPAE is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set # CONFIG_SOC_OMAPTI81XX is not set # CONFIG_SOC_OMAPAM33XX is not set # CONFIG_MACH_TI8148EVM is not set -# CONFIG_OMAP4_ERRATA_I688 is not set -# CONFIG_ARM_LPAE is not set +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set # CONFIG_MICREL_KS8995MA is not set # CONFIG_CHARGER_MANAGER is not set # CONFIG_MFD_DA9052_SPI is not set # CONFIG_MFD_DA9052_I2C is not set # CONFIG_MFD_S5M_CORE is not set # CONFIG_VIDEO_AS3645A is not set +# CONFIG_ARM_OMAP2PLUS_CPUFREQ is not set +# + diff --git a/config-arm-tegra b/config-arm-tegra index 9658d4989..ef4f53599 100644 --- a/config-arm-tegra +++ b/config-arm-tegra @@ -1,15 +1,22 @@ CONFIG_ARCH_TEGRA=y + +CONFIG_ARCH_TEGRA_2x_SOC=y +# CONFIG_ARCH_TEGRA_3x_SOC is not set +# CONFIG_ARM_LPAE is not set +CONFIG_TEGRA_PCI=y + CONFIG_MACH_HARMONY=y CONFIG_MACH_KAEN=y CONFIG_MACH_PAZ00=y +CONFIG_MACH_SEABOARD=y +CONFIG_MACH_TEGRA_DT=y CONFIG_MACH_TRIMSLICE=y CONFIG_MACH_WARIO=y CONFIG_MACH_TEGRA_DT=y +CONFIG_MACH_VENTANA=y + CONFIG_TEGRA_DEBUG_UARTD=y CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SMP=y -CONFIG_NR_CPUS=2 CONFIG_PREEMPT=y CONFIG_AEABI=y @@ -46,17 +53,17 @@ CONFIG_ARM_ERRATA_720789=y CONFIG_SMP_ON_UP=y CONFIG_LOCAL_TIMERS=y # CONFIG_THUMB2_KERNEL is not set -CONFIG_HW_PERF_EVENTS=y # CONFIG_NEON is not set # CONFIG_RFKILL_GPIO is not set CONFIG_GPIO_GENERIC_PLATFORM=y # CONFIG_GPIO_MCP23S08 is not set -CONFIG_KEYBOARD_TEGRA=y +# CONFIG_KEYBOARD_TEGRA is not set # CONFIG_MPCORE_WATCHDOG is not set CONFIG_USB_EHCI_TEGRA=y -CONFIG_RTC_DRV_TEGRA=m +CONFIG_RTC_DRV_TEGRA=y CONFIG_SND_SOC_TEGRA=m +CONFIG_SND_SOC_TEGRA_ALC5632=m CONFIG_SND_SOC_TEGRA_WM8903=m CONFIG_SND_SOC_TEGRA_TRIMSLICE=m @@ -64,38 +71,29 @@ CONFIG_MFD_NVEC=y # CONFIG_DEBUG_PREEMPT is not set # CONFIG_RCU_CPU_STALL_VERBOSE is not set # CONFIG_PREEMPT_TRACER is not set +# CONFIG_DEBUG_PINCTRL is not set CONFIG_KEYBOARD_NVEC=y CONFIG_SERIO_NVEC_PS2=y CONFIG_NVEC_POWER=y CONFIG_POWER_SUPPLY=y +CONFIG_NVEC_LEDS=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEBUG=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPU_FREQ_TABLE=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_PM=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y -CONFIG_CRYSTALHD=m +CONFIG_CRYPTO_DEV_TEGRA_AES=m -CONFIG_MACH_VENTANA=y CONFIG_PL310_ERRATA_753970=y -CONFIG_ARM_CPU_TOPOLOGY=y CONFIG_SCHED_MC=y CONFIG_SCHED_SMT=y CONFIG_LEDS_RENESAS_TPU=y -# CONFIG_ARCH_TEGRA_2x_SOC is not set -# CONFIG_ARCH_TEGRA_3x_SOC is not set -# CONFIG_ETHERNET is not set -# CONFIG_NET_VENDOR_BROADCOM is not set -# CONFIG_DVB_TDA1004X is not set -# CONFIG_DVB_PLL is not set -# CONFIG_SND_SOC_TEGRA_ALC5632 is not set +CONFIG_OF_GPIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_TEGRA_IOMMU_GART=y +CONFIG_TEGRA_IOMMU_SMMU=y diff --git a/config-generic b/config-generic index 7474f897f..a6508a90c 100644 --- a/config-generic +++ b/config-generic @@ -94,6 +94,7 @@ CONFIG_PCI_PRI=y CONFIG_PCI_PASID=y CONFIG_HT_IRQ=y CONFIG_PCI_MSI=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set CONFIG_PCIEPORTBUS=y CONFIG_PCIEAER=y CONFIG_PCIEASPM=y @@ -298,6 +299,7 @@ CONFIG_MTD_NAND_CS553X=m CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018 # CONFIG_MTD_NAND_GPIO is not set CONFIG_MTD_NAND_RICOH=m +# CONFIG_MTD_NAND_DOCG4 is not set CONFIG_MTD_REDBOOT_PARTS=m # CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set @@ -439,6 +441,7 @@ CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_BLK_DEV_IDEDMA=y # CONFIG_BLK_DEV_HD is not set +CONFIG_SCSI_VIRTIO=m CONFIG_VIRTIO_BLK=m CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=m @@ -539,6 +542,8 @@ CONFIG_SCSI_MPT2SAS=m CONFIG_SCSI_MPT2SAS_MAX_SGE=128 CONFIG_SCSI_MPT2SAS_LOGGING=y +CONFIG_SCSI_UFSHCD=m + CONFIG_SCSI_MVUMI=m CONFIG_SCSI_OSD_INITIATOR=m @@ -721,6 +726,7 @@ CONFIG_DM_MULTIPATH_QL=m CONFIG_DM_MULTIPATH_ST=m CONFIG_DM_RAID=m CONFIG_DM_FLAKEY=m +CONFIG_DM_VERITY=m # # Fusion MPT device support @@ -910,6 +916,7 @@ CONFIG_NETFILTER_XT_TARGET_CT=m CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m CONFIG_NETFILTER_XT_TARGET_MARK=m CONFIG_NETFILTER_XT_TARGET_NFLOG=m CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m @@ -988,6 +995,7 @@ CONFIG_NF_CONNTRACK_SIP=m CONFIG_NF_CONNTRACK_TFTP=m CONFIG_NF_CONNTRACK_IPV4=y CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set CONFIG_NF_CONNTRACK_TIMESTAMP=y CONFIG_NF_CONNTRACK_SNMP=m CONFIG_NF_NAT=m @@ -995,6 +1003,7 @@ CONFIG_NF_NAT_SNMP_BASIC=m CONFIG_NF_CT_PROTO_DCCP=m CONFIG_NF_CT_PROTO_SCTP=m CONFIG_NF_CT_NETLINK=m +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set CONFIG_NF_CT_PROTO_UDPLITE=m CONFIG_IP_NF_MATCH_AH=m @@ -1159,6 +1168,7 @@ CONFIG_NET_SCH_MQPRIO=m CONFIG_NET_SCH_MULTIQ=m CONFIG_NET_SCH_CHOKE=m CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_PLUG=m CONFIG_NET_CLS=y CONFIG_NET_CLS_ACT=y CONFIG_NET_CLS_BASIC=m @@ -1401,6 +1411,7 @@ CONFIG_FORCEDETH=m CONFIG_NET_VENDOR_OKI=y # CONFIG_PCH_GBE is not set +# CONFIG_PCH_PTP is not set CONFIG_NET_PACKET_ENGINE=y CONFIG_HAMACHI=m @@ -1470,6 +1481,7 @@ CONFIG_NET_VENDOR_XIRCOM=y CONFIG_PCMCIA_XIRC2PS=m CONFIG_PHYLIB=y +CONFIG_AMD_PHY=m CONFIG_BROADCOM_PHY=m CONFIG_CICADA_PHY=m CONFIG_DAVICOM_PHY=m @@ -1519,6 +1531,8 @@ CONFIG_IP1000=m CONFIG_MLX4_EN=m # CONFIG_MLX4_DEBUG is not set CONFIG_SFC=m +CONFIG_SFC_MCDI_MON=y +CONFIG_SFC_SRIOV=y CONFIG_SFC_MTD=y # CONFIG_FDDI is not set @@ -1591,10 +1605,13 @@ CONFIG_ATH5K_DEBUG=y # CONFIG_ATH5K_TRACER is not set CONFIG_ATH6KL=m CONFIG_ATH6KL_DEBUG=y +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m CONFIG_ATH9K=m CONFIG_ATH9K_PCI=y CONFIG_ATH9K_AHB=y # CONFIG_ATH9K_DEBUG is not set +# CONFIG_ATH9K_MAC_DEBUG is not set CONFIG_ATH9K_DEBUGFS=y CONFIG_ATH9K_HTC=m CONFIG_ATH9K_BTCOEX_SUPPORT=y @@ -1628,6 +1645,7 @@ CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y CONFIG_BRCMSMAC=m CONFIG_BRCMFMAC=m CONFIG_BRCMFMAC_SDIO=y +CONFIG_BRCMFMAC_USB=y # CONFIG_BRCMDBG is not set CONFIG_HERMES=m CONFIG_HERMES_CACHE_FW_ON_INIT=y @@ -1661,6 +1679,7 @@ CONFIG_IWLWIFI=m CONFIG_IWLWIFI_DEBUG=y CONFIG_IWLWIFI_DEBUGFS=y CONFIG_IWLWIFI_DEVICE_SVTOOL=y +# CONFIG_IWLWIFI_EXPERIMENTAL_MFP is not set # CONFIG_IWLWIFI_P2P is not set CONFIG_IWLEGACY=m CONFIG_IWLEGACY_DEBUG=y @@ -1701,10 +1720,12 @@ CONFIG_RT2800PCI_RT53XX=y CONFIG_RT73USB=m CONFIG_RTL8180=m CONFIG_RTL8187=m +# CONFIG_RTLWIFI_DEBUG is not set CONFIG_TMD_HERMES=m CONFIG_USB_ZD1201=m CONFIG_USB_NET_RNDIS_WLAN=m CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m CONFIG_USB_NET_SMSC75XX=m CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set @@ -2052,6 +2073,7 @@ CONFIG_KEYBOARD_ATKBD=y # CONFIG_KEYBOARD_QT2160 is not set # CONFIG_KEYBOARD_TCA6416 is not set # CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_OMAP4 is not set CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_PS2_TOUCHKIT is not set @@ -2062,6 +2084,7 @@ CONFIG_MOUSE_VSXXXAA=m CONFIG_MOUSE_APPLETOUCH=m CONFIG_MOUSE_BCM5974=m CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=m CONFIG_INPUT_JOYSTICK=y CONFIG_JOYSTICK_ANALOG=m CONFIG_JOYSTICK_A3D=m @@ -2098,6 +2121,7 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_AD7879 is not set CONFIG_TOUCHSCREEN_AD7879_I2C=m # CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set CONFIG_TOUCHSCREEN_DYNAPRO=m CONFIG_TOUCHSCREEN_EETI=m CONFIG_TOUCHSCREEN_EGALAX=m @@ -2107,6 +2131,7 @@ CONFIG_TOUCHSCREEN_GUNZE=m # CONFIG_TOUCHSCREEN_HAMPSHIRE is not set CONFIG_TOUCHSCREEN_HTCPEN=m CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_ILI210X=m CONFIG_TOUCHSCREEN_MTOUCH=m CONFIG_TOUCHSCREEN_MCS5000=m CONFIG_TOUCHSCREEN_MK712=m @@ -2337,12 +2362,14 @@ CONFIG_SENSORS_LM93=m CONFIG_SENSORS_LTC4245=m CONFIG_SENSORS_MAX1619=m CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MCP3021=m CONFIG_SENSORS_NTC_THERMISTOR=m CONFIG_SENSORS_PC87360=m CONFIG_SENSORS_PC87427=m CONFIG_SENSORS_PCF8591=m CONFIG_SENSORS_SHT15=m CONFIG_SENSORS_SIS5595=m +CONFIG_CHARGER_SMB347=m CONFIG_SENSORS_SMSC47M1=m CONFIG_SENSORS_SMSC47M192=m CONFIG_SENSORS_SMSC47B397=m @@ -2553,6 +2580,7 @@ CONFIG_VGA_ARB_MAX_GPUS=16 CONFIG_STUB_POULSBO=m # CONFIG_DRM_PSB is not set CONFIG_DRM=m +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set CONFIG_DRM_TDFX=m CONFIG_DRM_R128=m CONFIG_DRM_RADEON=m @@ -2569,6 +2597,7 @@ CONFIG_DRM_NOUVEAU_BACKLIGHT=y CONFIG_DRM_NOUVEAU_DEBUG=y CONFIG_DRM_I2C_CH7006=m CONFIG_DRM_I2C_SIL164=m +CONFIG_DRM_UDL=m CONFIG_DRM_VMWGFX=m # @@ -2675,6 +2704,7 @@ CONFIG_USB_KEENE=n # CONFIG_VIDEO_TIMBERDALE is not set # CONFIG_VIDEO_M5MOLS is not set +# CONFIG_EXYNOS_VIDEO is not set CONFIG_USB_VIDEO_CLASS=m CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y @@ -2842,6 +2872,7 @@ CONFIG_FB=y # CONFIG_FB_GEODE is not set # CONFIG_FB_HECUBA is not set # CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set CONFIG_FB_I810=m CONFIG_FB_I810_GTF=y CONFIG_FB_I810_I2C=y @@ -3109,8 +3140,10 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y # CONFIG_USB_EHCI_MV is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set CONFIG_USB_OHCI_HCD=y # CONFIG_USB_OHCI_HCD_SSB is not set +# CONFIG_USB_OHCI_HCD_PLATFORM is not set CONFIG_USB_UHCI_HCD=y CONFIG_USB_SL811_HCD=m CONFIG_USB_SL811_HCD_ISO=y @@ -3221,6 +3254,9 @@ CONFIG_HOLTEK_FF=y CONFIG_HID_SPEEDLINK=m CONFIG_HID_WIIMOTE=m CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_KYE=m +CONFIG_HID_SAITEK=m +CONFIG_HID_TIVO=m # # USB Imaging devices @@ -3356,6 +3392,7 @@ CONFIG_USB_SERIAL_SYMBOL=m CONFIG_USB_SERIAL_EDGEPORT=m CONFIG_USB_SERIAL_EDGEPORT_TI=m CONFIG_USB_SERIAL_EMPEG=m +# CONFIG_USB_SERIAL_F81232 is not set CONFIG_USB_SERIAL_FTDI_SIO=m CONFIG_USB_SERIAL_FUNSOFT=m CONFIG_USB_SERIAL_GARMIN=m @@ -3381,6 +3418,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y CONFIG_USB_SERIAL_KLSI=m CONFIG_USB_SERIAL_KOBIL_SCT=m CONFIG_USB_SERIAL_MCT_U232=m +# CONFIG_USB_SERIAL_METRO is not set CONFIG_USB_SERIAL_MOS7720=m CONFIG_USB_SERIAL_MOS7715_PARPORT=y # CONFIG_USB_SERIAL_ZIO is not set @@ -3520,6 +3558,7 @@ CONFIG_MFD_WM8400=m # CONFIG_MFD_TPS6586X is not set # CONFIG_MFD_TC3589X is not set # CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65217 is not set # # File systems @@ -3639,6 +3678,7 @@ CONFIG_SQUASHFS_ZLIB=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set CONFIG_SYSV_FS=m CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set @@ -3659,6 +3699,7 @@ CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V3_ACL=y @@ -3675,6 +3716,7 @@ CONFIG_EXPORTFS=y CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_SUNRPC_DEBUG=y CONFIG_RPCSEC_GSS_KRB5=m CONFIG_CIFS=m CONFIG_CIFS_STATS=y @@ -3883,6 +3925,7 @@ CONFIG_SECURITY_SELINUX_AVC_STATS=y # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set # CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set CONFIG_AUDIT=y CONFIG_AUDITSYSCALL=y # CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set @@ -3966,6 +4009,7 @@ CONFIG_CRYPTO_USER=m # CONFIG_CRC16=y CONFIG_CRC32=m +# CONFIG_CRC32_SELFTEST is not set CONFIG_CRC_CCITT=m CONFIG_CRC_ITU_T=m CONFIG_CRC_T10DIF=m @@ -4000,6 +4044,7 @@ CONFIG_FB_ATY128_BACKLIGHT=y CONFIG_FB_ATY_BACKLIGHT=y # CONFIG_BACKLIGHT_SAHARA is not set CONFIG_BACKLIGHT_WM831X=m +CONFIG_BACKLIGHT_LP855X=m CONFIG_LCD_CLASS_DEVICE=m CONFIG_LCD_PLATFORM=m @@ -4195,6 +4240,7 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_PCA955X is not set # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_S3C24XX is not set +# CONFIG_LEDS_PCA9633 is not set CONFIG_LEDS_DELL_NETBOOKS=m # CONFIG_LEDS_TCA6507 is not set # CONFIG_LEDS_OT200 is not set @@ -4271,6 +4317,7 @@ CONFIG_APM_POWER=m # CONFIG_WM831X_POWER is not set # CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2781 is not set # CONFIG_BATTERY_DS2782 is not set # CONFIG_BATTERY_SBS is not set # CONFIG_BATTERY_BQ20Z75 is not set @@ -4443,6 +4490,9 @@ CONFIG_ALTERA_STAPL=m # CONFIG_RTS5139 is not set # CONFIG_NVEC_LEDS is not set # CONFIG_VT6655 is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_RAMSTER is not set +# CONFIG_USB_WPAN_HCD is not set # # END OF STAGING @@ -4469,6 +4519,7 @@ CONFIG_STRIP_ASM_SYMS=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_RCU_TRACE is not set +# CONFIG_RCU_CPU_STALL_INFO is not set CONFIG_SPARSE_RCU_POINTER=y CONFIG_KSM=y @@ -4493,6 +4544,7 @@ CONFIG_PPS_CLIENT_GPIO=m CONFIG_NTP_PPS=y CONFIG_PTP_1588_CLOCK=m +CONFIG_PTP_1588_CLOCK_PCH=m CONFIG_CLEANCACHE=y @@ -4560,4 +4612,6 @@ CONFIG_BCMA_HOST_PCI=y # CONFIG_GOOGLE_FIRMWARE is not set CONFIG_IOMMU_SUPPORT=y +# CONFIG_HSI is not set + # CONFIG_PM_DEVFREQ is not set diff --git a/config-powerpc-generic b/config-powerpc-generic index 6b5498542..59e7d5c9e 100644 --- a/config-powerpc-generic +++ b/config-powerpc-generic @@ -360,3 +360,6 @@ CONFIG_RFKILL_GPIO=m # CONFIG_CPU_IDLE is not set CONFIG_STRICT_DEVMEM=y # CONFIG_V4L_RADIO_ISA_DRIVERS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_MPIC_MSGR is not set +# CONFIG_FA_DUMP is not set diff --git a/config-s390x b/config-s390x index f03942191..848709dfb 100644 --- a/config-s390x +++ b/config-s390x @@ -197,6 +197,7 @@ CONFIG_QETH_L3=m CONFIG_CRYPTO_SHA512_S390=m CONFIG_VIRTUALIZATION=y CONFIG_KVM=m +# CONFIG_KVM_S390_UCONTROL is not set CONFIG_S390_GUEST=y diff --git a/config-x86-32-generic b/config-x86-32-generic index 3f4fc346f..b00834482 100644 --- a/config-x86-32-generic +++ b/config-x86-32-generic @@ -154,6 +154,8 @@ CONFIG_OLPC_XO1_SCI=y # staging # CONFIG_FB_OLPC_DCON is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set + # CONFIG_SPARSE_IRQ is not set CONFIG_RCU_FANOUT=32 @@ -207,3 +209,7 @@ CONFIG_I2O_BUS=m # CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set # CONFIG_INPUT_GP2A is not set # CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_GEOS is not set +# CONFIG_NET5501 is not set +# CONFIG_GPIO_SODAVILLE is not set +# CONFIG_BACKLIGHT_OT200 is not set diff --git a/config-x86-generic b/config-x86-generic index cf5e3c611..181e3e92f 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -86,6 +86,7 @@ CONFIG_ACPI_APEI_MEMORY_FAILURE=y # CONFIG_ACPI_APEI_EINJ is not set CONFIG_ACPI_IPMI=m CONFIG_ACPI_CUSTOM_METHOD=m +CONFIG_ACPI_BGRT=m CONFIG_X86_ACPI_CPUFREQ=y CONFIG_X86_PCC_CPUFREQ=y @@ -247,6 +248,7 @@ CONFIG_XEN_BALLOON=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_SAVE_RESTORE=y CONFIG_HVC_XEN=y +CONFIG_HVC_XEN_FRONTEND=y CONFIG_XEN_FBDEV_FRONTEND=y CONFIG_XEN_BLKDEV_FRONTEND=m CONFIG_XEN_NETDEV_FRONTEND=m @@ -264,6 +266,7 @@ CONFIG_XEN_GNTDEV=m CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m CONFIG_XEN_SELFBALLOONING=y CONFIG_XEN_PCIDEV_BACKEND=m +CONFIG_XEN_ACPI_PROCESSOR=m CONFIG_MTD_ESB2ROM=m CONFIG_MTD_CK804XROM=m @@ -389,7 +392,11 @@ CONFIG_SCHED_SMT=y CONFIG_CC_STACKPROTECTOR=y CONFIG_RELOCATABLE=y -# CONFIG_HYPERV is not set +CONFIG_HYPERV=m +CONFIG_HYPERV_UTILS=m +CONFIG_HID_HYPERV_MOUSE=m +CONFIG_HYPERV_NET=m +CONFIG_HYPERV_STORAGE=m # Depends on PCI CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m @@ -400,3 +407,5 @@ CONFIG_DRM_GMA500=m # Maybe enable in debug kernels? # CONFIG_DEBUG_NMI_SELFTEST is not set + +CONFIG_APPLE_GMUX=m diff --git a/config-x86_64-generic b/config-x86_64-generic index a334a3736..0b01f9f44 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -1,5 +1,6 @@ CONFIG_64BIT=y +# CONFIG_X86_X32 is not set # CONFIG_MK8 is not set # CONFIG_MPSC is not set CONFIG_GENERIC_CPU=y @@ -50,6 +51,7 @@ CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m CONFIG_CRYPTO_SHA1_SSSE3=m CONFIG_CRYPTO_BLOWFISH_X86_64=m CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m +CONFIG_CRYPTO_CAMELLIA_X86_64=m # CONFIG_I2C_ALI1535 is not set # CONFIG_I2C_ALI1563 is not set diff --git a/disable-hid-battery.patch b/disable-hid-battery.patch deleted file mode 100644 index 98fe2139e..000000000 --- a/disable-hid-battery.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- linux-2.6.43.noarch.orig/drivers/hid/Kconfig -+++ linux-2.6.43.noarch/drivers/hid/Kconfig -@@ -34,7 +34,7 @@ config HID - config HID_BATTERY_STRENGTH - bool - depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY -- default y -+ default n - - config HIDRAW - bool "/dev/hidraw raw HID device support" diff --git a/drivers-media-update.patch b/drivers-media-update.patch index 15eba7350..e69de29bb 100644 --- a/drivers-media-update.patch +++ b/drivers-media-update.patch @@ -1,38187 +0,0 @@ -Driver updates with all media stuff - -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/az6007.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/az6007.c -@@ -0,0 +1,957 @@ -+/* -+ * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones -+ * -+ * Copyright (c) Henry Wang -+ * -+ * This driver was made publicly available by Terratec, at: -+ * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz -+ * The original driver's license is GPL, as declared with MODULE_LICENSE() -+ * -+ * Copyright (c) 2010-2011 Mauro Carvalho Chehab -+ * Driver modified by in order to work with upstream drxk driver, and -+ * tons of bugs got fixed. -+ * -+ * 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 under version 2 of the License. -+ * -+ * 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. -+ */ -+ -+#include "drxk.h" -+#include "mt2063.h" -+#include "dvb_ca_en50221.h" -+ -+#define DVB_USB_LOG_PREFIX "az6007" -+#include "dvb-usb.h" -+ -+/* debug */ -+int dvb_usb_az6007_debug; -+module_param_named(debug, dvb_usb_az6007_debug, int, 0644); -+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." -+ DVB_USB_DEBUG_STATUS); -+ -+#define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args) -+#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args) -+#define deb_rc(args...) dprintk(dvb_usb_az6007_debug, 0x04, args) -+#define deb_fe(args...) dprintk(dvb_usb_az6007_debug, 0x08, args) -+ -+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -+ -+/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/ -+ -+#define FX2_OED 0xb5 -+#define AZ6007_READ_DATA 0xb7 -+#define AZ6007_I2C_RD 0xb9 -+#define AZ6007_POWER 0xbc -+#define AZ6007_I2C_WR 0xbd -+#define FX2_SCON1 0xc0 -+#define AZ6007_TS_THROUGH 0xc7 -+#define AZ6007_READ_IR 0xb4 -+ -+struct az6007_device_state { -+ struct mutex mutex; -+ struct mutex ca_mutex; -+ struct dvb_ca_en50221 ca; -+ unsigned warm:1; -+ int (*gate_ctrl) (struct dvb_frontend *, int); -+ unsigned char data[4096]; -+}; -+ -+static struct drxk_config terratec_h7_drxk = { -+ .adr = 0x29, -+ .parallel_ts = true, -+ .dynamic_clk = true, -+ .single_master = true, -+ .enable_merr_cfg = true, -+ .no_i2c_bridge = false, -+ .chunk_size = 64, -+ .mpeg_out_clk_strength = 0x02, -+ .microcode_name = "dvb-usb-terratec-h7-drxk.fw", -+}; -+ -+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) -+{ -+ struct dvb_usb_adapter *adap = fe->sec_priv; -+ struct az6007_device_state *st; -+ int status = 0; -+ -+ deb_info("%s: %s\n", __func__, enable ? "enable" : "disable"); -+ -+ if (!adap) -+ return -EINVAL; -+ -+ st = adap->dev->priv; -+ -+ if (!st) -+ return -EINVAL; -+ -+ if (enable) -+ status = st->gate_ctrl(fe, 1); -+ else -+ status = st->gate_ctrl(fe, 0); -+ -+ return status; -+} -+ -+static struct mt2063_config az6007_mt2063_config = { -+ .tuner_address = 0x60, -+ .refclock = 36125000, -+}; -+ -+static int __az6007_read(struct usb_device *udev, u8 req, u16 value, -+ u16 index, u8 *b, int blen) -+{ -+ int ret; -+ -+ ret = usb_control_msg(udev, -+ usb_rcvctrlpipe(udev, 0), -+ req, -+ USB_TYPE_VENDOR | USB_DIR_IN, -+ value, index, b, blen, 5000); -+ if (ret < 0) { -+ warn("usb read operation failed. (%d)", ret); -+ return -EIO; -+ } -+ -+ deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, -+ index); -+ debug_dump(b, blen, deb_xfer); -+ -+ return ret; -+} -+ -+static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value, -+ u16 index, u8 *b, int blen) -+{ -+ struct az6007_device_state *st = d->priv; -+ int ret; -+ -+ if (mutex_lock_interruptible(&st->mutex) < 0) -+ return -EAGAIN; -+ -+ ret = __az6007_read(d->udev, req, value, index, b, blen); -+ -+ mutex_unlock(&st->mutex); -+ -+ return ret; -+} -+ -+static int __az6007_write(struct usb_device *udev, u8 req, u16 value, -+ u16 index, u8 *b, int blen) -+{ -+ int ret; -+ -+ deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, -+ index); -+ debug_dump(b, blen, deb_xfer); -+ -+ if (blen > 64) { -+ err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n", -+ blen); -+ return -EOPNOTSUPP; -+ } -+ -+ ret = usb_control_msg(udev, -+ usb_sndctrlpipe(udev, 0), -+ req, -+ USB_TYPE_VENDOR | USB_DIR_OUT, -+ value, index, b, blen, 5000); -+ if (ret != blen) { -+ err("usb write operation failed. (%d)", ret); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value, -+ u16 index, u8 *b, int blen) -+{ -+ struct az6007_device_state *st = d->priv; -+ int ret; -+ -+ if (mutex_lock_interruptible(&st->mutex) < 0) -+ return -EAGAIN; -+ -+ ret = __az6007_write(d->udev, req, value, index, b, blen); -+ -+ mutex_unlock(&st->mutex); -+ -+ return ret; -+} -+ -+static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -+{ -+ struct dvb_usb_device *d = adap->dev; -+ -+ deb_info("%s: %s", __func__, onoff ? "enable" : "disable"); -+ -+ return az6007_write(d, 0xbc, onoff, 0, NULL, 0); -+} -+ -+/* remote control stuff (does not work with my box) */ -+static int az6007_rc_query(struct dvb_usb_device *d) -+{ -+ struct az6007_device_state *st = d->priv; -+ unsigned code = 0; -+ -+ az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); -+ -+ if (st->data[1] == 0x44) -+ return 0; -+ -+ if ((st->data[1] ^ st->data[2]) == 0xff) -+ code = st->data[1]; -+ else -+ code = st->data[1] << 8 | st->data[2]; -+ -+ if ((st->data[3] ^ st->data[4]) == 0xff) -+ code = code << 8 | st->data[3]; -+ else -+ code = code << 16 | st->data[3] << 8 | st->data[4]; -+ -+ rc_keydown(d->rc_dev, code, st->data[5]); -+ -+ return 0; -+} -+ -+static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, -+ int slot, -+ int address) -+{ -+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; -+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; -+ -+ int ret; -+ u8 req; -+ u16 value; -+ u16 index; -+ int blen; -+ u8 *b; -+ -+ if (slot != 0) -+ return -EINVAL; -+ -+ b = kmalloc(12, GFP_KERNEL); -+ if (!b) -+ return -ENOMEM; -+ -+ mutex_lock(&state->ca_mutex); -+ -+ req = 0xC1; -+ value = address; -+ index = 0; -+ blen = 1; -+ -+ ret = az6007_read(d, req, value, index, b, blen); -+ if (ret < 0) { -+ warn("usb in operation failed. (%d)", ret); -+ ret = -EINVAL; -+ } else { -+ ret = b[0]; -+ } -+ -+ mutex_unlock(&state->ca_mutex); -+ kfree(b); -+ return ret; -+} -+ -+static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, -+ int slot, -+ int address, -+ u8 value) -+{ -+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; -+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; -+ -+ int ret; -+ u8 req; -+ u16 value1; -+ u16 index; -+ int blen; -+ -+ deb_info("%s %d", __func__, slot); -+ if (slot != 0) -+ return -EINVAL; -+ -+ mutex_lock(&state->ca_mutex); -+ req = 0xC2; -+ value1 = address; -+ index = value; -+ blen = 0; -+ -+ ret = az6007_write(d, req, value1, index, NULL, blen); -+ if (ret != 0) -+ warn("usb out operation failed. (%d)", ret); -+ -+ mutex_unlock(&state->ca_mutex); -+ return ret; -+} -+ -+static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, -+ int slot, -+ u8 address) -+{ -+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; -+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; -+ -+ int ret; -+ u8 req; -+ u16 value; -+ u16 index; -+ int blen; -+ u8 *b; -+ -+ if (slot != 0) -+ return -EINVAL; -+ -+ b = kmalloc(12, GFP_KERNEL); -+ if (!b) -+ return -ENOMEM; -+ -+ mutex_lock(&state->ca_mutex); -+ -+ req = 0xC3; -+ value = address; -+ index = 0; -+ blen = 2; -+ -+ ret = az6007_read(d, req, value, index, b, blen); -+ if (ret < 0) { -+ warn("usb in operation failed. (%d)", ret); -+ ret = -EINVAL; -+ } else { -+ if (b[0] == 0) -+ warn("Read CI IO error"); -+ -+ ret = b[1]; -+ deb_info("read cam data = %x from 0x%x", b[1], value); -+ } -+ -+ mutex_unlock(&state->ca_mutex); -+ kfree(b); -+ return ret; -+} -+ -+static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, -+ int slot, -+ u8 address, -+ u8 value) -+{ -+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; -+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; -+ -+ int ret; -+ u8 req; -+ u16 value1; -+ u16 index; -+ int blen; -+ -+ if (slot != 0) -+ return -EINVAL; -+ -+ mutex_lock(&state->ca_mutex); -+ req = 0xC4; -+ value1 = address; -+ index = value; -+ blen = 0; -+ -+ ret = az6007_write(d, req, value1, index, NULL, blen); -+ if (ret != 0) { -+ warn("usb out operation failed. (%d)", ret); -+ goto failed; -+ } -+ -+failed: -+ mutex_unlock(&state->ca_mutex); -+ return ret; -+} -+ -+static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) -+{ -+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; -+ -+ int ret; -+ u8 req; -+ u16 value; -+ u16 index; -+ int blen; -+ u8 *b; -+ -+ b = kmalloc(12, GFP_KERNEL); -+ if (!b) -+ return -ENOMEM; -+ -+ req = 0xC8; -+ value = 0; -+ index = 0; -+ blen = 1; -+ -+ ret = az6007_read(d, req, value, index, b, blen); -+ if (ret < 0) { -+ warn("usb in operation failed. (%d)", ret); -+ ret = -EIO; -+ } else{ -+ ret = b[0]; -+ } -+ kfree(b); -+ return ret; -+} -+ -+static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) -+{ -+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; -+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; -+ -+ int ret, i; -+ u8 req; -+ u16 value; -+ u16 index; -+ int blen; -+ -+ mutex_lock(&state->ca_mutex); -+ -+ req = 0xC6; -+ value = 1; -+ index = 0; -+ blen = 0; -+ -+ ret = az6007_write(d, req, value, index, NULL, blen); -+ if (ret != 0) { -+ warn("usb out operation failed. (%d)", ret); -+ goto failed; -+ } -+ -+ msleep(500); -+ req = 0xC6; -+ value = 0; -+ index = 0; -+ blen = 0; -+ -+ ret = az6007_write(d, req, value, index, NULL, blen); -+ if (ret != 0) { -+ warn("usb out operation failed. (%d)", ret); -+ goto failed; -+ } -+ -+ for (i = 0; i < 15; i++) { -+ msleep(100); -+ -+ if (CI_CamReady(ca, slot)) { -+ deb_info("CAM Ready"); -+ break; -+ } -+ } -+ msleep(5000); -+ -+failed: -+ mutex_unlock(&state->ca_mutex); -+ return ret; -+} -+ -+static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -+{ -+ return 0; -+} -+ -+static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -+{ -+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; -+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; -+ -+ int ret; -+ u8 req; -+ u16 value; -+ u16 index; -+ int blen; -+ -+ deb_info("%s", __func__); -+ mutex_lock(&state->ca_mutex); -+ req = 0xC7; -+ value = 1; -+ index = 0; -+ blen = 0; -+ -+ ret = az6007_write(d, req, value, index, NULL, blen); -+ if (ret != 0) { -+ warn("usb out operation failed. (%d)", ret); -+ goto failed; -+ } -+ -+failed: -+ mutex_unlock(&state->ca_mutex); -+ return ret; -+} -+ -+static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -+{ -+ struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; -+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; -+ int ret; -+ u8 req; -+ u16 value; -+ u16 index; -+ int blen; -+ u8 *b; -+ -+ b = kmalloc(12, GFP_KERNEL); -+ if (!b) -+ return -ENOMEM; -+ mutex_lock(&state->ca_mutex); -+ -+ req = 0xC5; -+ value = 0; -+ index = 0; -+ blen = 1; -+ -+ ret = az6007_read(d, req, value, index, b, blen); -+ if (ret < 0) { -+ warn("usb in operation failed. (%d)", ret); -+ ret = -EIO; -+ } else -+ ret = 0; -+ -+ if (!ret && b[0] == 1) { -+ ret = DVB_CA_EN50221_POLL_CAM_PRESENT | -+ DVB_CA_EN50221_POLL_CAM_READY; -+ } -+ -+ mutex_unlock(&state->ca_mutex); -+ kfree(b); -+ return ret; -+} -+ -+ -+static void az6007_ci_uninit(struct dvb_usb_device *d) -+{ -+ struct az6007_device_state *state; -+ -+ deb_info("%s", __func__); -+ -+ if (NULL == d) -+ return; -+ -+ state = (struct az6007_device_state *)d->priv; -+ if (NULL == state) -+ return; -+ -+ if (NULL == state->ca.data) -+ return; -+ -+ dvb_ca_en50221_release(&state->ca); -+ -+ memset(&state->ca, 0, sizeof(state->ca)); -+} -+ -+ -+static int az6007_ci_init(struct dvb_usb_adapter *a) -+{ -+ struct dvb_usb_device *d = a->dev; -+ struct az6007_device_state *state = (struct az6007_device_state *)d->priv; -+ int ret; -+ -+ deb_info("%s", __func__); -+ -+ mutex_init(&state->ca_mutex); -+ -+ state->ca.owner = THIS_MODULE; -+ state->ca.read_attribute_mem = az6007_ci_read_attribute_mem; -+ state->ca.write_attribute_mem = az6007_ci_write_attribute_mem; -+ state->ca.read_cam_control = az6007_ci_read_cam_control; -+ state->ca.write_cam_control = az6007_ci_write_cam_control; -+ state->ca.slot_reset = az6007_ci_slot_reset; -+ state->ca.slot_shutdown = az6007_ci_slot_shutdown; -+ state->ca.slot_ts_enable = az6007_ci_slot_ts_enable; -+ state->ca.poll_slot_status = az6007_ci_poll_slot_status; -+ state->ca.data = d; -+ -+ ret = dvb_ca_en50221_init(&a->dvb_adap, -+ &state->ca, -+ 0, /* flags */ -+ 1);/* n_slots */ -+ if (ret != 0) { -+ err("Cannot initialize CI: Error %d.", ret); -+ memset(&state->ca, 0, sizeof(state->ca)); -+ return ret; -+ } -+ -+ deb_info("CI initialized."); -+ -+ return 0; -+} -+ -+static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) -+{ -+ struct az6007_device_state *st = d->priv; -+ int ret; -+ -+ ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6); -+ memcpy(mac, st->data, sizeof(mac)); -+ -+ if (ret > 0) -+ deb_info("%s: mac is %02x:%02x:%02x:%02x:%02x:%02x\n", -+ __func__, mac[0], mac[1], mac[2], -+ mac[3], mac[4], mac[5]); -+ -+ return ret; -+} -+ -+static int az6007_frontend_attach(struct dvb_usb_adapter *adap) -+{ -+ struct az6007_device_state *st = adap->dev->priv; -+ -+ deb_info("attaching demod drxk"); -+ -+ adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk, -+ &adap->dev->i2c_adap); -+ if (!adap->fe_adap[0].fe) -+ return -EINVAL; -+ -+ adap->fe_adap[0].fe->sec_priv = adap; -+ st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl; -+ adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; -+ -+ az6007_ci_init(adap); -+ -+ return 0; -+} -+ -+static int az6007_tuner_attach(struct dvb_usb_adapter *adap) -+{ -+ deb_info("attaching tuner mt2063"); -+ -+ /* Attach mt2063 to DVB-C frontend */ -+ if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) -+ adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1); -+ if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe, -+ &az6007_mt2063_config, -+ &adap->dev->i2c_adap)) -+ return -EINVAL; -+ -+ if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) -+ adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0); -+ -+ return 0; -+} -+ -+int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) -+{ -+ struct az6007_device_state *st = d->priv; -+ int ret; -+ -+ deb_info("%s()\n", __func__); -+ -+ if (!st->warm) { -+ mutex_init(&st->mutex); -+ -+ ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0); -+ if (ret < 0) -+ return ret; -+ msleep(60); -+ ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); -+ if (ret < 0) -+ return ret; -+ msleep(100); -+ ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0); -+ if (ret < 0) -+ return ret; -+ msleep(20); -+ ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0); -+ if (ret < 0) -+ return ret; -+ -+ msleep(400); -+ ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0); -+ if (ret < 0) -+ return ret; -+ msleep(150); -+ ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0); -+ if (ret < 0) -+ return ret; -+ msleep(430); -+ ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); -+ if (ret < 0) -+ return ret; -+ -+ st->warm = true; -+ -+ return 0; -+ } -+ -+ if (!onoff) -+ return 0; -+ -+ az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0); -+ az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0); -+ -+ return 0; -+} -+ -+/* I2C */ -+static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], -+ int num) -+{ -+ struct dvb_usb_device *d = i2c_get_adapdata(adap); -+ struct az6007_device_state *st = d->priv; -+ int i, j, len; -+ int ret = 0; -+ u16 index; -+ u16 value; -+ int length; -+ u8 req, addr; -+ -+ if (mutex_lock_interruptible(&st->mutex) < 0) -+ return -EAGAIN; -+ -+ for (i = 0; i < num; i++) { -+ addr = msgs[i].addr << 1; -+ if (((i + 1) < num) -+ && (msgs[i].len == 1) -+ && (!msgs[i].flags & I2C_M_RD) -+ && (msgs[i + 1].flags & I2C_M_RD) -+ && (msgs[i].addr == msgs[i + 1].addr)) { -+ /* -+ * A write + read xfer for the same address, where -+ * the first xfer has just 1 byte length. -+ * Need to join both into one operation -+ */ -+ if (dvb_usb_az6007_debug & 2) -+ printk(KERN_DEBUG -+ "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ", -+ addr, msgs[i].len, msgs[i + 1].len); -+ req = AZ6007_I2C_RD; -+ index = msgs[i].buf[0]; -+ value = addr | (1 << 8); -+ length = 6 + msgs[i + 1].len; -+ len = msgs[i + 1].len; -+ ret = __az6007_read(d->udev, req, value, index, -+ st->data, length); -+ if (ret >= len) { -+ for (j = 0; j < len; j++) { -+ msgs[i + 1].buf[j] = st->data[j + 5]; -+ if (dvb_usb_az6007_debug & 2) -+ printk(KERN_CONT -+ "0x%02x ", -+ msgs[i + 1].buf[j]); -+ } -+ } else -+ ret = -EIO; -+ i++; -+ } else if (!(msgs[i].flags & I2C_M_RD)) { -+ /* write bytes */ -+ if (dvb_usb_az6007_debug & 2) -+ printk(KERN_DEBUG -+ "az6007 I2C xfer write addr=0x%x len=%d: ", -+ addr, msgs[i].len); -+ req = AZ6007_I2C_WR; -+ index = msgs[i].buf[0]; -+ value = addr | (1 << 8); -+ length = msgs[i].len - 1; -+ len = msgs[i].len - 1; -+ if (dvb_usb_az6007_debug & 2) -+ printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]); -+ for (j = 0; j < len; j++) { -+ st->data[j] = msgs[i].buf[j + 1]; -+ if (dvb_usb_az6007_debug & 2) -+ printk(KERN_CONT "0x%02x ", -+ st->data[j]); -+ } -+ ret = __az6007_write(d->udev, req, value, index, -+ st->data, length); -+ } else { -+ /* read bytes */ -+ if (dvb_usb_az6007_debug & 2) -+ printk(KERN_DEBUG -+ "az6007 I2C xfer read addr=0x%x len=%d: ", -+ addr, msgs[i].len); -+ req = AZ6007_I2C_RD; -+ index = msgs[i].buf[0]; -+ value = addr; -+ length = msgs[i].len + 6; -+ len = msgs[i].len; -+ ret = __az6007_read(d->udev, req, value, index, -+ st->data, length); -+ for (j = 0; j < len; j++) { -+ msgs[i].buf[j] = st->data[j + 5]; -+ if (dvb_usb_az6007_debug & 2) -+ printk(KERN_CONT -+ "0x%02x ", st->data[j + 5]); -+ } -+ } -+ if (dvb_usb_az6007_debug & 2) -+ printk(KERN_CONT "\n"); -+ if (ret < 0) -+ goto err; -+ } -+err: -+ mutex_unlock(&st->mutex); -+ -+ if (ret < 0) { -+ info("%s ERROR: %i", __func__, ret); -+ return ret; -+ } -+ return num; -+} -+ -+static u32 az6007_i2c_func(struct i2c_adapter *adapter) -+{ -+ return I2C_FUNC_I2C; -+} -+ -+static struct i2c_algorithm az6007_i2c_algo = { -+ .master_xfer = az6007_i2c_xfer, -+ .functionality = az6007_i2c_func, -+}; -+ -+int az6007_identify_state(struct usb_device *udev, -+ struct dvb_usb_device_properties *props, -+ struct dvb_usb_device_description **desc, int *cold) -+{ -+ int ret; -+ u8 *mac; -+ -+ mac = kmalloc(6, GFP_ATOMIC); -+ if (!mac) -+ return -ENOMEM; -+ -+ /* Try to read the mac address */ -+ ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6); -+ if (ret == 6) -+ *cold = 0; -+ else -+ *cold = 1; -+ -+ kfree(mac); -+ -+ if (*cold) { -+ __az6007_write(udev, 0x09, 1, 0, NULL, 0); -+ __az6007_write(udev, 0x00, 0, 0, NULL, 0); -+ __az6007_write(udev, 0x00, 0, 0, NULL, 0); -+ } -+ -+ deb_info("Device is on %s state\n", *cold ? "warm" : "cold"); -+ return 0; -+} -+ -+static struct dvb_usb_device_properties az6007_properties; -+ -+static void az6007_usb_disconnect(struct usb_interface *intf) -+{ -+ struct dvb_usb_device *d = usb_get_intfdata(intf); -+ az6007_ci_uninit(d); -+ dvb_usb_device_exit(intf); -+} -+ -+static int az6007_usb_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ return dvb_usb_device_init(intf, &az6007_properties, -+ THIS_MODULE, NULL, adapter_nr); -+} -+ -+static struct usb_device_id az6007_usb_table[] = { -+ {USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)}, -+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)}, -+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)}, -+ {0}, -+}; -+ -+MODULE_DEVICE_TABLE(usb, az6007_usb_table); -+ -+static struct dvb_usb_device_properties az6007_properties = { -+ .caps = DVB_USB_IS_AN_I2C_ADAPTER, -+ .usb_ctrl = CYPRESS_FX2, -+ .firmware = "dvb-usb-terratec-h7-az6007.fw", -+ .no_reconnect = 1, -+ .size_of_priv = sizeof(struct az6007_device_state), -+ .identify_state = az6007_identify_state, -+ .num_adapters = 1, -+ .adapter = { -+ { -+ .num_frontends = 1, -+ .fe = {{ -+ .streaming_ctrl = az6007_streaming_ctrl, -+ .tuner_attach = az6007_tuner_attach, -+ .frontend_attach = az6007_frontend_attach, -+ -+ /* parameter for the MPEG2-data transfer */ -+ .stream = { -+ .type = USB_BULK, -+ .count = 10, -+ .endpoint = 0x02, -+ .u = { -+ .bulk = { -+ .buffersize = 4096, -+ } -+ } -+ }, -+ } } -+ } }, -+ .power_ctrl = az6007_power_ctrl, -+ .read_mac_address = az6007_read_mac_addr, -+ -+ .rc.core = { -+ .rc_interval = 400, -+ .rc_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, -+ .module_name = "az6007", -+ .rc_query = az6007_rc_query, -+ .allowed_protos = RC_TYPE_NEC, -+ }, -+ .i2c_algo = &az6007_i2c_algo, -+ -+ .num_device_descs = 2, -+ .devices = { -+ { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)", -+ .cold_ids = { &az6007_usb_table[0], NULL }, -+ .warm_ids = { NULL }, -+ }, -+ { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)", -+ .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL }, -+ .warm_ids = { NULL }, -+ }, -+ { NULL }, -+ } -+}; -+ -+/* usb specific object needed to register this driver with the usb subsystem */ -+static struct usb_driver az6007_usb_driver = { -+ .name = "dvb_usb_az6007", -+ .probe = az6007_usb_probe, -+ .disconnect = az6007_usb_disconnect, -+ .id_table = az6007_usb_table, -+}; -+ -+/* module stuff */ -+static int __init az6007_usb_module_init(void) -+{ -+ int result; -+ deb_info("az6007 usb module init\n"); -+ -+ result = usb_register(&az6007_usb_driver); -+ if (result) { -+ err("usb_register failed. (%d)", result); -+ return result; -+ } -+ -+ return 0; -+} -+ -+static void __exit az6007_usb_module_exit(void) -+{ -+ /* deregister this driver from the USB subsystem */ -+ deb_info("az6007 usb module exit\n"); -+ usb_deregister(&az6007_usb_driver); -+} -+ -+module_init(az6007_usb_module_init); -+module_exit(az6007_usb_module_exit); -+ -+MODULE_AUTHOR("Henry Wang "); -+MODULE_AUTHOR("Mauro Carvalho Chehab "); -+MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones"); -+MODULE_VERSION("1.1"); -+MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/az6007.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/az6007.h -@@ -0,0 +1,18 @@ -+#ifndef _DVB_USB_AZ6007_H_ -+#define _DVB_USB_AZ6007_H_ -+ -+#define DVB_USB_LOG_PREFIX "az6007" -+#include "dvb-usb.h" -+ -+ -+extern int dvb_usb_az6007_debug; -+#define deb_info(args...) dprintk(dvb_usb_az6007_debug,0x01,args) -+#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug,0x02,args) -+#define deb_rc(args...) dprintk(dvb_usb_az6007_debug,0x04,args) -+#define deb_fe(args...) dprintk(dvb_usb_az6007_debug,0x08,args) -+ -+ -+extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); -+extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -+ -+#endif -Index: linux-3.3.x86_64/drivers/media/common/tuners/mt2063.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/common/tuners/mt2063.c -+++ linux-3.3.x86_64/drivers/media/common/tuners/mt2063.c -@@ -350,7 +350,7 @@ static int MT2063_Sleep(struct dvb_front - /* - * ToDo: Add code here to implement a OS blocking - */ -- msleep(10); -+ msleep(100); - - return 0; - } -@@ -2226,7 +2226,7 @@ static struct dvb_tuner_ops mt2063_ops = - .info = { - .name = "MT2063 Silicon Tuner", - .frequency_min = 45000000, -- .frequency_max = 850000000, -+ .frequency_max = 865000000, - .frequency_step = 0, - }, - -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/dvb-usb-ids.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/dvb-usb-ids.h -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/dvb-usb-ids.h -@@ -51,6 +51,7 @@ - #define USB_VID_PINNACLE 0x2304 - #define USB_VID_PCTV 0x2013 - #define USB_VID_PIXELVIEW 0x1554 -+#define USB_VID_REALTEK 0x0bda - #define USB_VID_TECHNOTREND 0x0b48 - #define USB_VID_TERRATEC 0x0ccd - #define USB_VID_TELESTAR 0x10b9 -@@ -75,11 +76,14 @@ - #define USB_PID_AFATECH_AF9005 0x9020 - #define USB_PID_AFATECH_AF9015_9015 0x9015 - #define USB_PID_AFATECH_AF9015_9016 0x9016 -+#define USB_PID_AFATECH_AF9035 0x9035 -+#define USB_PID_AFATECH_AF9035_2 0x1001 - #define USB_PID_TREKSTOR_DVBT 0x901b - #define USB_VID_ALINK_DTU 0xf170 - #define USB_PID_ANSONIC_DVBT_USB 0x6000 - #define USB_PID_ANYSEE 0x861f - #define USB_PID_AZUREWAVE_AD_TU700 0x3237 -+#define USB_PID_AZUREWAVE_6007 0x0ccd - #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 - #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 - #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 -@@ -125,6 +129,8 @@ - #define USB_PID_E3C_EC168_3 0xfffb - #define USB_PID_E3C_EC168_4 0x1001 - #define USB_PID_E3C_EC168_5 0x1002 -+#define USB_PID_FREECOM_DVBT 0x0160 -+#define USB_PID_FREECOM_DVBT_2 0x0161 - #define USB_PID_UNIWILL_STK7700P 0x6003 - #define USB_PID_GENIUS_TVGO_DVB_T03 0x4012 - #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 -@@ -148,6 +154,7 @@ - #define USB_PID_KWORLD_VSTREAM_WARM 0x17df - #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 - #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 -+#define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093 - #define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097 - #define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099 - #define USB_PID_TWINHAN_VP7041_COLD 0x3201 -@@ -217,6 +224,11 @@ - #define USB_PID_AVERMEDIA_A850T 0x850b - #define USB_PID_AVERMEDIA_A805 0xa805 - #define USB_PID_AVERMEDIA_A815M 0x815a -+#define USB_PID_AVERMEDIA_A835 0xa835 -+#define USB_PID_AVERMEDIA_B835 0xb835 -+#define USB_PID_AVERMEDIA_1867 0x1867 -+#define USB_PID_AVERMEDIA_A867 0xa867 -+#define USB_PID_AVERMEDIA_TWINSTAR 0x0825 - #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 - #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d - #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a -@@ -226,6 +238,8 @@ - #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 - #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 - #define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab -+#define USB_PID_TERRATEC_H7 0x10b4 -+#define USB_PID_TERRATEC_H7_2 0x10a3 - #define USB_PID_TERRATEC_T3 0x10a0 - #define USB_PID_TERRATEC_T5 0x10a1 - #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e -@@ -249,6 +263,8 @@ - #define USB_PID_PCTV_400E 0x020f - #define USB_PID_PCTV_450E 0x0222 - #define USB_PID_PCTV_452E 0x021f -+#define USB_PID_REALTEK_RTL2831U 0x2831 -+#define USB_PID_REALTEK_RTL2832U 0x2832 - #define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007 - #define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a - #define USB_PID_NEBULA_DIGITV 0x0201 -Index: linux-3.3.x86_64/drivers/media/dvb/ddbridge/ddbridge-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/ddbridge/ddbridge-core.c -+++ linux-3.3.x86_64/drivers/media/dvb/ddbridge/ddbridge-core.c -@@ -578,6 +578,7 @@ static int demod_attach_drxk(struct ddb_ - struct drxk_config config; - - memset(&config, 0, sizeof(config)); -+ config.microcode_name = "drxk_a3.mc"; - config.adr = 0x29 + (input->nr & 1); - - fe = input->fe = dvb_attach(drxk_attach, &config, i2c); -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/drxk_hard.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/drxk_hard.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/drxk_hard.c -@@ -28,7 +28,6 @@ - #include - #include - #include --#include - #include - - #include "dvb_frontend.h" -@@ -91,10 +90,6 @@ bool IsA1WithRomCode(struct drxk_state * - #define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03) - #endif - --#ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH --#define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06) --#endif -- - #define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700 - #define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500 - -@@ -650,9 +645,6 @@ static int init_state(struct drxk_state - u32 ulQual83 = DEFAULT_MER_83; - u32 ulQual93 = DEFAULT_MER_93; - -- u32 ulDVBTStaticTSClock = 1; -- u32 ulDVBCStaticTSClock = 1; -- - u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT; - u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT; - -@@ -662,7 +654,6 @@ static int init_state(struct drxk_state - u32 ulGPIOCfg = 0x0113; - u32 ulInvertTSClock = 0; - u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH; -- u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH; - u32 ulDVBTBitrate = 50000000; - u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8; - -@@ -815,8 +806,7 @@ static int init_state(struct drxk_state - state->m_invertSTR = false; /* If TRUE; invert STR signals */ - state->m_invertVAL = false; /* If TRUE; invert VAL signals */ - state->m_invertCLK = (ulInvertTSClock != 0); /* If TRUE; invert CLK signals */ -- state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0); -- state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0); -+ - /* If TRUE; static MPEG clockrate will be used; - otherwise clockrate will adapt to the bitrate of the TS */ - -@@ -824,7 +814,6 @@ static int init_state(struct drxk_state - state->m_DVBCBitrate = ulDVBCBitrate; - - state->m_TSDataStrength = (ulTSDataStrength & 0x07); -- state->m_TSClockkStrength = (ulTSClockkStrength & 0x07); - - /* Maximum bitrate in b/s in case static clockrate is selected */ - state->m_mpegTsStaticBitrate = 19392658; -@@ -1189,6 +1178,7 @@ static int MPEGTSConfigurePins(struct dr - int status = -1; - u16 sioPdrMclkCfg = 0; - u16 sioPdrMdxCfg = 0; -+ u16 err_cfg = 0; - - dprintk(1, ": mpeg %s, %s mode\n", - mpegEnable ? "enable" : "disable", -@@ -1254,12 +1244,17 @@ static int MPEGTSConfigurePins(struct dr - status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg); - if (status < 0) - goto error; -- status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000); /* Disable */ -+ -+ if (state->enable_merr_cfg) -+ err_cfg = sioPdrMdxCfg; -+ -+ status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg); - if (status < 0) - goto error; -- status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000); /* Disable */ -+ status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg); - if (status < 0) - goto error; -+ - if (state->m_enableParallel == true) { - /* paralel -> enable MD1 to MD7 */ - status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg); -@@ -6070,9 +6065,7 @@ static int init_drxk(struct drxk_state * - if (status < 0) - goto error; - -- if (!state->microcode_name) -- load_microcode(state, "drxk_a3.mc"); -- else -+ if (state->microcode_name) - load_microcode(state, state->microcode_name); - - /* disable token-ring bus through OFDM block for possible ucode upload */ -@@ -6323,15 +6316,12 @@ static int drxk_get_tune_settings(struct - switch (p->delivery_system) { - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: -+ case SYS_DVBT: - sets->min_delay_ms = 3000; - sets->max_drift = 0; - sets->step_size = 0; - return 0; - default: -- /* -- * For DVB-T, let it use the default DVB core way, that is: -- * fepriv->step_size = fe->ops.info.frequency_stepsize * 2 -- */ - return -EINVAL; - } - } -@@ -6391,6 +6381,21 @@ struct dvb_frontend *drxk_attach(const s - state->antenna_gpio = config->antenna_gpio; - state->antenna_dvbt = config->antenna_dvbt; - state->m_ChunkSize = config->chunk_size; -+ state->enable_merr_cfg = config->enable_merr_cfg; -+ -+ if (config->dynamic_clk) { -+ state->m_DVBTStaticCLK = 0; -+ state->m_DVBCStaticCLK = 0; -+ } else { -+ state->m_DVBTStaticCLK = 1; -+ state->m_DVBCStaticCLK = 1; -+ } -+ -+ -+ if (config->mpeg_out_clk_strength) -+ state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07; -+ else -+ state->m_TSClockkStrength = 0x06; - - if (config->parallel_ts) - state->m_enableParallel = true; -Index: linux-3.3.x86_64/drivers/media/dvb/ngene/ngene-cards.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/ngene/ngene-cards.c -+++ linux-3.3.x86_64/drivers/media/dvb/ngene/ngene-cards.c -@@ -216,6 +216,7 @@ static int demod_attach_drxk(struct ngen - struct drxk_config config; - - memset(&config, 0, sizeof(config)); -+ config.microcode_name = "drxk_a3.mc"; - config.adr = 0x29 + (chan->number ^ 2); - - chan->fe = dvb_attach(drxk_attach, &config, i2c); -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/drxk.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/drxk.h -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/drxk.h -@@ -7,15 +7,19 @@ - /** - * struct drxk_config - Configure the initial parameters for DRX-K - * -- * adr: I2C Address of the DRX-K -- * parallel_ts: true means that the device uses parallel TS, -+ * @adr: I2C Address of the DRX-K -+ * @parallel_ts: True means that the device uses parallel TS, - * Serial otherwise. -- * single_master: Device is on the single master mode -- * no_i2c_bridge: Don't switch the I2C bridge to talk with tuner -- * antenna_gpio: GPIO bit used to control the antenna -- * antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1 -+ * @dynamic_clk: True means that the clock will be dynamically -+ * adjusted. Static clock otherwise. -+ * @enable_merr_cfg: Enable SIO_PDR_PERR_CFG/SIO_PDR_MVAL_CFG. -+ * @single_master: Device is on the single master mode -+ * @no_i2c_bridge: Don't switch the I2C bridge to talk with tuner -+ * @antenna_gpio: GPIO bit used to control the antenna -+ * @antenna_dvbt: GPIO bit for changing antenna to DVB-C. A value of 1 - * means that 1=DVBC, 0 = DVBT. Zero means the opposite. -- * microcode_name: Name of the firmware file with the microcode -+ * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength. -+ * @microcode_name: Name of the firmware file with the microcode - * - * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is - * UIO-3. -@@ -25,11 +29,14 @@ struct drxk_config { - bool single_master; - bool no_i2c_bridge; - bool parallel_ts; -+ bool dynamic_clk; -+ bool enable_merr_cfg; - - bool antenna_dvbt; - u16 antenna_gpio; - -- int chunk_size; -+ u8 mpeg_out_clk_strength; -+ int chunk_size; - - const char *microcode_name; - }; -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/drxk_hard.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/drxk_hard.h -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/drxk_hard.h -@@ -332,6 +332,7 @@ struct drxk_state { - - u16 UIO_mask; /* Bits used by UIO */ - -+ bool enable_merr_cfg; - bool single_master; - bool no_i2c_bridge; - bool antenna_dvbt; -Index: linux-3.3.x86_64/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c -+++ linux-3.3.x86_64/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c -@@ -18,6 +18,8 @@ - */ - - static struct rc_map_table nec_terratec_cinergy_xs[] = { -+ -+ /* Terratec Grey IR, with most keys in orange */ - { 0x1441, KEY_HOME}, - { 0x1401, KEY_POWER2}, - -@@ -78,6 +80,56 @@ static struct rc_map_table nec_terratec_ - { 0x144e, KEY_REWIND}, - { 0x144f, KEY_FASTFORWARD}, - { 0x145c, KEY_NEXT}, -+ -+ /* Terratec Black IR, with most keys in black */ -+ { 0x04eb01, KEY_POWER2}, -+ -+ { 0x04eb02, KEY_1}, -+ { 0x04eb03, KEY_2}, -+ { 0x04eb04, KEY_3}, -+ { 0x04eb05, KEY_4}, -+ { 0x04eb06, KEY_5}, -+ { 0x04eb07, KEY_6}, -+ { 0x04eb08, KEY_7}, -+ { 0x04eb09, KEY_8}, -+ { 0x04eb0a, KEY_9}, -+ { 0x04eb0c, KEY_0}, -+ -+ { 0x04eb0b, KEY_TEXT}, /* TXT */ -+ { 0x04eb0d, KEY_REFRESH}, /* Refresh */ -+ -+ { 0x04eb0e, KEY_HOME}, -+ { 0x04eb0f, KEY_EPG}, -+ -+ { 0x04eb10, KEY_UP}, -+ { 0x04eb11, KEY_LEFT}, -+ { 0x04eb12, KEY_OK}, -+ { 0x04eb13, KEY_RIGHT}, -+ { 0x04eb14, KEY_DOWN}, -+ -+ { 0x04eb15, KEY_BACKSPACE}, -+ { 0x04eb16, KEY_INFO}, -+ -+ { 0x04eb17, KEY_RED}, -+ { 0x04eb18, KEY_GREEN}, -+ { 0x04eb19, KEY_YELLOW}, -+ { 0x04eb1a, KEY_BLUE}, -+ -+ { 0x04eb1c, KEY_VOLUMEUP}, -+ { 0x04eb1e, KEY_VOLUMEDOWN}, -+ -+ { 0x04eb1d, KEY_MUTE}, -+ -+ { 0x04eb1b, KEY_CHANNELUP}, -+ { 0x04eb1f, KEY_CHANNELDOWN}, -+ -+ { 0x04eb40, KEY_RECORD}, -+ { 0x04eb4c, KEY_PLAY}, -+ { 0x04eb58, KEY_PAUSE}, -+ -+ { 0x04eb54, KEY_REWIND}, -+ { 0x04eb48, KEY_STOP}, -+ { 0x04eb5c, KEY_NEXT}, - }; - - static struct rc_map_list nec_terratec_cinergy_xs_map = { -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/Kconfig -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/Kconfig -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/Kconfig -@@ -361,6 +361,14 @@ config DVB_USB_EC168 - help - Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. - -+config DVB_USB_AZ6007 -+ tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" -+ depends on DVB_USB -+ select DVB_DRXK if !DVB_FE_CUSTOMISE -+ select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE -+ help -+ Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers. -+ - config DVB_USB_AZ6027 - tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" - depends on DVB_USB -@@ -378,6 +386,7 @@ config DVB_USB_LME2510 - select DVB_IX2505V if !DVB_FE_CUSTOMISE - select DVB_STV0299 if !DVB_FE_CUSTOMISE - select DVB_PLL if !DVB_FE_CUSTOMISE -+ select DVB_M88RS2000 if !DVB_FE_CUSTOMISE - help - Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . - -@@ -403,3 +412,25 @@ config DVB_USB_MXL111SF - select VIDEO_TVEEPROM - help - Say Y here to support the MxL111SF USB2.0 DTV receiver. -+ -+config DVB_USB_RTL28XXU -+ tristate "Realtek RTL28xxU DVB USB support" -+ depends on DVB_USB && EXPERIMENTAL -+ select DVB_RTL2830 -+ select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE -+ select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE -+ select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE -+ help -+ Say Y here to support the Realtek RTL28xxU DVB USB receiver. -+ -+config DVB_USB_AF9035 -+ tristate "Afatech AF9035 DVB-T USB2.0 support" -+ depends on DVB_USB -+ select DVB_AF9033 -+ select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE -+ select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE -+ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE -+ select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE -+ help -+ Say Y here to support the Afatech AF9035 based DVB USB receiver. -+ -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/Makefile -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/Makefile -@@ -54,7 +54,6 @@ obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb - dvb-usb-opera-objs = opera1.o - obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o - -- - dvb-usb-af9005-objs = af9005.o af9005-fe.o - obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o - -@@ -88,6 +87,9 @@ obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-f - dvb-usb-ec168-objs = ec168.o - obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o - -+dvb-usb-az6007-objs = az6007.o -+obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o -+ - dvb-usb-az6027-objs = az6027.o - obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o - -@@ -105,8 +107,15 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-us - obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o - obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o - --ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -+dvb-usb-rtl28xxu-objs = rtl28xxu.o -+obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o -+ -+dvb-usb-af9035-objs = af9035.o -+obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o -+ -+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core -+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ - # due to tuner-xc3028 --ccflags-y += -Idrivers/media/common/tuners --EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci -+ccflags-y += -I$(srctree)/drivers/media/common/tuners -+ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci - -Index: linux-3.3.x86_64/drivers/media/video/omap/omap_vout.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/omap/omap_vout.c -+++ linux-3.3.x86_64/drivers/media/video/omap/omap_vout.c -@@ -2268,13 +2268,12 @@ static struct platform_driver omap_vout_ - .driver = { - .name = VOUT_NAME, - }, -- .probe = omap_vout_probe, - .remove = omap_vout_remove, - }; - - static int __init omap_vout_init(void) - { -- if (platform_driver_register(&omap_vout_driver) != 0) { -+ if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) { - printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n"); - return -EINVAL; - } -Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/compat.xml -=================================================================== ---- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/compat.xml -+++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/compat.xml -@@ -2393,6 +2393,10 @@ details. - to the User controls class. - - -+ -+ Added the device_caps field to struct v4l2_capabilities and added the new -+ V4L2_CAP_DEVICE_CAPS capability. -+ - - - -Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/v4l2.xml -=================================================================== ---- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/v4l2.xml -+++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/v4l2.xml -@@ -128,6 +128,13 @@ structs, ioctls) must be noted in more d - applications. --> - - -+ 3.3 -+ 2012-01-11 -+ hv -+ Added device_caps field to struct v4l2_capabilities. -+ -+ -+ - 3.2 - 2011-08-26 - hv -@@ -417,7 +424,7 @@ and discussions on the V4L mailing list. - - - Video for Linux Two API Specification -- Revision 3.2 -+ Revision 3.3 - - - &sub-common; -Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/vidioc-querycap.xml -=================================================================== ---- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/vidioc-querycap.xml -+++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/vidioc-querycap.xml -@@ -124,12 +124,35 @@ printf ("Version: %u.%u.%u\n", - - __u32 - capabilities -- Device capabilities, see . -+ Available capabilities of the physical device as a whole, see . The same physical device can export -+ multiple devices in /dev (e.g. /dev/videoX, /dev/vbiY and /dev/radioZ). -+ The capabilities field should contain a union -+ of all capabilities available around the several V4L2 devices exported -+ to userspace. -+ For all those devices the capabilities field -+ returns the same set of capabilities. This allows applications to open -+ just one of the devices (typically the video device) and discover whether -+ video, vbi and/or radio are also supported. -+ - - - __u32 -- reserved[4] -+ device_caps -+ Device capabilities of the opened device, see . Should contain the available capabilities -+ of that specific device node. So, for example, device_caps -+ of a radio device will only contain radio related capabilities and -+ no video or vbi capabilities. This field is only set if the capabilities -+ field contains the V4L2_CAP_DEVICE_CAPS capability. -+ Only the capabilities field can have the -+ V4L2_CAP_DEVICE_CAPS capability, device_caps -+ will never set V4L2_CAP_DEVICE_CAPS. -+ -+ -+ -+ __u32 -+ reserved[3] - Reserved for future extensions. Drivers must set - this array to zero. - -@@ -276,6 +299,13 @@ linkend="async">asynchronous I/O - The device supports the streaming I/O method. - -+ -+ V4L2_CAP_DEVICE_CAPS -+ 0x80000000 -+ The driver fills the device_caps -+ field. This capability can only appear in the capabilities -+ field and never in the device_caps field. -+ - - - -Index: linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-417.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx231xx/cx231xx-417.c -+++ linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-417.c -@@ -1686,7 +1686,6 @@ static struct v4l2_capability pvr_capabi - .capabilities = (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE), -- .reserved = {0, 0, 0, 0} - }; - static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -Index: linux-3.3.x86_64/drivers/media/video/pvrusb2/pvrusb2-v4l2.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/pvrusb2/pvrusb2-v4l2.c -+++ linux-3.3.x86_64/drivers/media/video/pvrusb2/pvrusb2-v4l2.c -@@ -96,7 +96,6 @@ static struct v4l2_capability pvr_capabi - .capabilities = (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | - V4L2_CAP_READWRITE), -- .reserved = {0,0,0,0} - }; - - static struct v4l2_fmtdesc pvr_fmtdesc [] = { -Index: linux-3.3.x86_64/drivers/media/video/v4l2-ioctl.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/v4l2-ioctl.c -+++ linux-3.3.x86_64/drivers/media/video/v4l2-ioctl.c -@@ -260,6 +260,8 @@ static const char *v4l2_ioctls[] = { - [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", - [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", - -+ [_IOC_NR(VIDIOC_DECODER_CMD)] = "VIDIOC_DECODER_CMD", -+ [_IOC_NR(VIDIOC_TRY_DECODER_CMD)] = "VIDIOC_TRY_DECODER_CMD", - [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", - [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", - -@@ -540,10 +542,12 @@ static long __video_do_ioctl(struct file - if (!ret) - dbgarg(cmd, "driver=%s, card=%s, bus=%s, " - "version=0x%08x, " -- "capabilities=0x%08x\n", -+ "capabilities=0x%08x, " -+ "device_caps=0x%08x\n", - cap->driver, cap->card, cap->bus_info, - cap->version, -- cap->capabilities); -+ cap->capabilities, -+ cap->device_caps); - break; - } - -@@ -1762,6 +1766,32 @@ static long __video_do_ioctl(struct file - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } -+ case VIDIOC_DECODER_CMD: -+ { -+ struct v4l2_decoder_cmd *p = arg; -+ -+ if (!ops->vidioc_decoder_cmd) -+ break; -+ if (ret_prio) { -+ ret = ret_prio; -+ break; -+ } -+ ret = ops->vidioc_decoder_cmd(file, fh, p); -+ if (!ret) -+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); -+ break; -+ } -+ case VIDIOC_TRY_DECODER_CMD: -+ { -+ struct v4l2_decoder_cmd *p = arg; -+ -+ if (!ops->vidioc_try_decoder_cmd) -+ break; -+ ret = ops->vidioc_try_decoder_cmd(file, fh, p); -+ if (!ret) -+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); -+ break; -+ } - case VIDIOC_G_PARM: - { - struct v4l2_streamparm *p = arg; -@@ -1909,7 +1939,13 @@ static long __video_do_ioctl(struct file - { - if (!ops->vidioc_log_status) - break; -+ if (vfd->v4l2_dev) -+ pr_info("%s: ================= START STATUS =================\n", -+ vfd->v4l2_dev->name); - ret = ops->vidioc_log_status(file, fh); -+ if (vfd->v4l2_dev) -+ pr_info("%s: ================== END STATUS ==================\n", -+ vfd->v4l2_dev->name); - break; - } - #ifdef CONFIG_VIDEO_ADV_DEBUG -@@ -2419,7 +2455,7 @@ video_usercopy(struct file *file, unsign - /* Handles IOCTL */ - err = func(file, cmd, parg); - if (err == -ENOIOCTLCMD) -- err = -EINVAL; -+ err = -ENOTTY; - - if (has_array_args) { - *kernel_ptr = user_ptr; -Index: linux-3.3.x86_64/include/linux/videodev2.h -=================================================================== ---- linux-3.3.x86_64.orig/include/linux/videodev2.h -+++ linux-3.3.x86_64/include/linux/videodev2.h -@@ -235,16 +235,25 @@ struct v4l2_fract { - __u32 denominator; - }; - --/* -- * D R I V E R C A P A B I L I T I E S -- */ -+/** -+ * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP -+ * -+ * @driver: name of the driver module (e.g. "bttv") -+ * @card: name of the card (e.g. "Hauppauge WinTV") -+ * @bus_info: name of the bus (e.g. "PCI:" + pci_name(pci_dev) ) -+ * @version: KERNEL_VERSION -+ * @capabilities: capabilities of the physical device as a whole -+ * @device_caps: capabilities accessed via this particular device (node) -+ * @reserved: reserved fields for future extensions -+ */ - struct v4l2_capability { -- __u8 driver[16]; /* i.e. "bttv" */ -- __u8 card[32]; /* i.e. "Hauppauge WinTV" */ -- __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ -- __u32 version; /* should use KERNEL_VERSION() */ -- __u32 capabilities; /* Device capabilities */ -- __u32 reserved[4]; -+ __u8 driver[16]; -+ __u8 card[32]; -+ __u8 bus_info[32]; -+ __u32 version; -+ __u32 capabilities; -+ __u32 device_caps; -+ __u32 reserved[3]; - }; - - /* Values for 'capabilities' field */ -@@ -274,6 +283,8 @@ struct v4l2_capability { - #define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ - #define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ - -+#define V4L2_CAP_DEVICE_CAPS 0x80000000 /* sets device capabilities field */ -+ - /* - * V I D E O I M A G E F O R M A T - */ -@@ -751,20 +762,20 @@ struct v4l2_crop { - - /* Selection targets */ - --/* current cropping area */ --#define V4L2_SEL_TGT_CROP_ACTIVE 0 --/* default cropping area */ --#define V4L2_SEL_TGT_CROP_DEFAULT 1 --/* cropping bounds */ --#define V4L2_SEL_TGT_CROP_BOUNDS 2 --/* current composing area */ --#define V4L2_SEL_TGT_COMPOSE_ACTIVE 256 --/* default composing area */ --#define V4L2_SEL_TGT_COMPOSE_DEFAULT 257 --/* composing bounds */ --#define V4L2_SEL_TGT_COMPOSE_BOUNDS 258 --/* current composing area plus all padding pixels */ --#define V4L2_SEL_TGT_COMPOSE_PADDED 259 -+/* Current cropping area */ -+#define V4L2_SEL_TGT_CROP_ACTIVE 0x0000 -+/* Default cropping area */ -+#define V4L2_SEL_TGT_CROP_DEFAULT 0x0001 -+/* Cropping bounds */ -+#define V4L2_SEL_TGT_CROP_BOUNDS 0x0002 -+/* Current composing area */ -+#define V4L2_SEL_TGT_COMPOSE_ACTIVE 0x0100 -+/* Default composing area */ -+#define V4L2_SEL_TGT_COMPOSE_DEFAULT 0x0101 -+/* Composing bounds */ -+#define V4L2_SEL_TGT_COMPOSE_BOUNDS 0x0102 -+/* Current composing area plus all padding pixels */ -+#define V4L2_SEL_TGT_COMPOSE_PADDED 0x0103 - - /** - * struct v4l2_selection - selection info -@@ -774,7 +785,7 @@ struct v4l2_crop { - * @r: coordinates of selection window - * @reserved: for future use, rounds structure size to 64 bytes, set to zero - * -- * Hardware may use multiple helper window to process a video stream. -+ * Hardware may use multiple helper windows to process a video stream. - * The structure is used to exchange this selection areas between - * an application and a driver. - */ -@@ -1125,6 +1136,7 @@ struct v4l2_ext_controls { - #define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */ - #define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator control class */ - #define V4L2_CTRL_CLASS_FLASH 0x009c0000 /* Camera flash controls */ -+#define V4L2_CTRL_CLASS_JPEG 0x009d0000 /* JPEG-compression controls */ - - #define V4L2_CTRL_ID_MASK (0x0fffffff) - #define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) -@@ -1396,6 +1408,16 @@ enum v4l2_mpeg_audio_ac3_bitrate { - V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17, - V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18, - }; -+#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK (V4L2_CID_MPEG_BASE+112) -+enum v4l2_mpeg_audio_dec_playback { -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO = 0, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO = 1, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT = 2, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT = 3, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO = 4, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5, -+}; -+#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113) - - /* MPEG video controls specific to multiplexed streams */ - #define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200) -@@ -1446,6 +1468,9 @@ enum v4l2_mpeg_video_multi_slice_mode { - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2, - }; - #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) -+#define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) -+#define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) -+ - #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) - #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) - #define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP (V4L2_CID_MPEG_BASE+302) -@@ -1734,6 +1759,29 @@ enum v4l2_flash_strobe_source { - #define V4L2_CID_FLASH_CHARGE (V4L2_CID_FLASH_CLASS_BASE + 11) - #define V4L2_CID_FLASH_READY (V4L2_CID_FLASH_CLASS_BASE + 12) - -+/* JPEG-class control IDs defined by V4L2 */ -+#define V4L2_CID_JPEG_CLASS_BASE (V4L2_CTRL_CLASS_JPEG | 0x900) -+#define V4L2_CID_JPEG_CLASS (V4L2_CTRL_CLASS_JPEG | 1) -+ -+#define V4L2_CID_JPEG_CHROMA_SUBSAMPLING (V4L2_CID_JPEG_CLASS_BASE + 1) -+enum v4l2_jpeg_chroma_subsampling { -+ V4L2_JPEG_CHROMA_SUBSAMPLING_444 = 0, -+ V4L2_JPEG_CHROMA_SUBSAMPLING_422 = 1, -+ V4L2_JPEG_CHROMA_SUBSAMPLING_420 = 2, -+ V4L2_JPEG_CHROMA_SUBSAMPLING_411 = 3, -+ V4L2_JPEG_CHROMA_SUBSAMPLING_410 = 4, -+ V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY = 5, -+}; -+#define V4L2_CID_JPEG_RESTART_INTERVAL (V4L2_CID_JPEG_CLASS_BASE + 2) -+#define V4L2_CID_JPEG_COMPRESSION_QUALITY (V4L2_CID_JPEG_CLASS_BASE + 3) -+ -+#define V4L2_CID_JPEG_ACTIVE_MARKER (V4L2_CID_JPEG_CLASS_BASE + 4) -+#define V4L2_JPEG_ACTIVE_MARKER_APP0 (1 << 0) -+#define V4L2_JPEG_ACTIVE_MARKER_APP1 (1 << 1) -+#define V4L2_JPEG_ACTIVE_MARKER_COM (1 << 16) -+#define V4L2_JPEG_ACTIVE_MARKER_DQT (1 << 17) -+#define V4L2_JPEG_ACTIVE_MARKER_DHT (1 << 18) -+ - /* - * T U N I N G - */ -@@ -1897,6 +1945,54 @@ struct v4l2_encoder_cmd { - }; - }; - -+/* Decoder commands */ -+#define V4L2_DEC_CMD_START (0) -+#define V4L2_DEC_CMD_STOP (1) -+#define V4L2_DEC_CMD_PAUSE (2) -+#define V4L2_DEC_CMD_RESUME (3) -+ -+/* Flags for V4L2_DEC_CMD_START */ -+#define V4L2_DEC_CMD_START_MUTE_AUDIO (1 << 0) -+ -+/* Flags for V4L2_DEC_CMD_PAUSE */ -+#define V4L2_DEC_CMD_PAUSE_TO_BLACK (1 << 0) -+ -+/* Flags for V4L2_DEC_CMD_STOP */ -+#define V4L2_DEC_CMD_STOP_TO_BLACK (1 << 0) -+#define V4L2_DEC_CMD_STOP_IMMEDIATELY (1 << 1) -+ -+/* Play format requirements (returned by the driver): */ -+ -+/* The decoder has no special format requirements */ -+#define V4L2_DEC_START_FMT_NONE (0) -+/* The decoder requires full GOPs */ -+#define V4L2_DEC_START_FMT_GOP (1) -+ -+/* The structure must be zeroed before use by the application -+ This ensures it can be extended safely in the future. */ -+struct v4l2_decoder_cmd { -+ __u32 cmd; -+ __u32 flags; -+ union { -+ struct { -+ __u64 pts; -+ } stop; -+ -+ struct { -+ /* 0 or 1000 specifies normal speed, -+ 1 specifies forward single stepping, -+ -1 specifies backward single stepping, -+ >1: playback at speed/1000 of the normal speed, -+ <-1: reverse playback at (-speed/1000) of the normal speed. */ -+ __s32 speed; -+ __u32 format; -+ } start; -+ -+ struct { -+ __u32 data[16]; -+ } raw; -+ }; -+}; - #endif - - -@@ -2307,6 +2403,11 @@ struct v4l2_create_buffers { - #define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection) - #define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection) - -+/* Experimental, these two ioctls may change over the next couple of kernel -+ versions. */ -+#define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd) -+#define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd) -+ - /* Reminder: when adding new ioctls please add support for them to - drivers/media/video/v4l2-compat-ioctl32.c as well! */ - -Index: linux-3.3.x86_64/drivers/media/video/vivi.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/vivi.c -+++ linux-3.3.x86_64/drivers/media/video/vivi.c -@@ -819,8 +819,9 @@ static int vidioc_querycap(struct file * - strcpy(cap->driver, "vivi"); - strcpy(cap->card, "vivi"); - strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); -- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \ -+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; -+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; - } - -@@ -958,14 +959,6 @@ static int vidioc_streamoff(struct file - return vb2_streamoff(&dev->vb_vidq, i); - } - --static int vidioc_log_status(struct file *file, void *priv) --{ -- struct vivi_dev *dev = video_drvdata(file); -- -- v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name); -- return 0; --} -- - static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) - { - return 0; -@@ -1008,17 +1001,6 @@ static int vidioc_s_input(struct file *f - return 0; - } - --static int vidioc_subscribe_event(struct v4l2_fh *fh, -- struct v4l2_event_subscription *sub) --{ -- switch (sub->type) { -- case V4L2_EVENT_CTRL: -- return v4l2_event_subscribe(fh, sub, 0); -- default: -- return -EINVAL; -- } --} -- - /* --- controls ---------------------------------------------- */ - - static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -@@ -1057,17 +1039,10 @@ static unsigned int - vivi_poll(struct file *file, struct poll_table_struct *wait) - { - struct vivi_dev *dev = video_drvdata(file); -- struct v4l2_fh *fh = file->private_data; - struct vb2_queue *q = &dev->vb_vidq; -- unsigned int res; - - dprintk(dev, 1, "%s\n", __func__); -- res = vb2_poll(q, file, wait); -- if (v4l2_event_pending(fh)) -- res |= POLLPRI; -- else -- poll_wait(file, &fh->wait, wait); -- return res; -+ return vb2_poll(q, file, wait); - } - - static int vivi_close(struct file *file) -@@ -1209,8 +1184,8 @@ static const struct v4l2_ioctl_ops vivi_ - .vidioc_s_input = vidioc_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, -- .vidioc_log_status = vidioc_log_status, -- .vidioc_subscribe_event = vidioc_subscribe_event, -+ .vidioc_log_status = v4l2_ctrl_log_status, -+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - }; - -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-driver.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-driver.h -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-driver.h -@@ -331,6 +331,7 @@ struct ivtv_stream { - struct ivtv *itv; /* for ease of use */ - const char *name; /* name of the stream */ - int type; /* stream type */ -+ u32 caps; /* V4L2 capabilities */ - - struct v4l2_fh *fh; /* pointer to the streaming filehandle */ - spinlock_t qlock; /* locks access to the queues */ -@@ -630,6 +631,16 @@ struct ivtv { - - struct v4l2_device v4l2_dev; - struct cx2341x_handler cxhdl; -+ struct { -+ /* PTS/Frame count control cluster */ -+ struct v4l2_ctrl *ctrl_pts; -+ struct v4l2_ctrl *ctrl_frame; -+ }; -+ struct { -+ /* Audio Playback control cluster */ -+ struct v4l2_ctrl *ctrl_audio_playback; -+ struct v4l2_ctrl *ctrl_audio_multilingual_playback; -+ }; - struct v4l2_ctrl_handler hdl_gpio; - struct v4l2_subdev sd_gpio; /* GPIO sub-device */ - u16 instance; -@@ -649,7 +660,6 @@ struct ivtv { - u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ - u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ - -- - /* Locking */ - spinlock_t lock; /* lock access to this struct */ - struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-ioctl.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-ioctl.c -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-ioctl.c -@@ -246,34 +246,40 @@ static int ivtv_validate_speed(int cur_s - } - - static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, -- struct video_command *vc, int try) -+ struct v4l2_decoder_cmd *dc, int try) - { - struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; - -- switch (vc->cmd) { -- case VIDEO_CMD_PLAY: { -- vc->flags = 0; -- vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); -- if (vc->play.speed < 0) -- vc->play.format = VIDEO_PLAY_FMT_GOP; -+ switch (dc->cmd) { -+ case V4L2_DEC_CMD_START: { -+ dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO; -+ dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed); -+ if (dc->start.speed < 0) -+ dc->start.format = V4L2_DEC_START_FMT_GOP; -+ else -+ dc->start.format = V4L2_DEC_START_FMT_NONE; -+ if (dc->start.speed != 500 && dc->start.speed != 1500) -+ dc->flags = dc->start.speed == 1000 ? 0 : -+ V4L2_DEC_CMD_START_MUTE_AUDIO; - if (try) break; - -+ itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO; - if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) - return -EBUSY; - if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { - /* forces ivtv_set_speed to be called */ - itv->speed = 0; - } -- return ivtv_start_decoding(id, vc->play.speed); -+ return ivtv_start_decoding(id, dc->start.speed); - } - -- case VIDEO_CMD_STOP: -- vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; -- if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) -- vc->stop.pts = 0; -+ case V4L2_DEC_CMD_STOP: -+ dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK; -+ if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) -+ dc->stop.pts = 0; - if (try) break; - if (atomic_read(&itv->decoding) == 0) - return 0; -@@ -281,22 +287,22 @@ static int ivtv_video_command(struct ivt - return -EBUSY; - - itv->output_mode = OUT_NONE; -- return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); -+ return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts); - -- case VIDEO_CMD_FREEZE: -- vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; -+ case V4L2_DEC_CMD_PAUSE: -+ dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK; - if (try) break; - if (itv->output_mode != OUT_MPG) - return -EBUSY; - if (atomic_read(&itv->decoding) > 0) { - ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, -- (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); -+ (dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0); - set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); - } - break; - -- case VIDEO_CMD_CONTINUE: -- vc->flags = 0; -+ case V4L2_DEC_CMD_RESUME: -+ dc->flags = 0; - if (try) break; - if (itv->output_mode != OUT_MPG) - return -EBUSY; -@@ -754,12 +760,15 @@ static int ivtv_s_register(struct file * - - static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) - { -- struct ivtv *itv = fh2id(fh)->itv; -+ struct ivtv_open_id *id = fh2id(file->private_data); -+ struct ivtv *itv = id->itv; -+ struct ivtv_stream *s = &itv->streams[id->type]; - - strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); - strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); -- vcap->capabilities = itv->v4l2_cap; /* capabilities */ -+ vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS; -+ vcap->device_caps = s->caps; - return 0; - } - -@@ -1476,8 +1485,6 @@ static int ivtv_log_status(struct file * - struct v4l2_audio audin; - int i; - -- IVTV_INFO("================= START STATUS CARD #%d =================\n", -- itv->instance); - IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); - if (itv->hw_flags & IVTV_HW_TVEEPROM) { - struct tveeprom tv; -@@ -1501,13 +1508,6 @@ static int ivtv_log_status(struct file * - "YUV Frames", - "Passthrough", - }; -- static const char * const audio_modes[5] = { -- "Stereo", -- "Left", -- "Right", -- "Mono", -- "Swapped" -- }; - static const char * const alpha_mode[4] = { - "None", - "Global", -@@ -1536,9 +1536,6 @@ static int ivtv_log_status(struct file * - ivtv_get_output(itv, itv->active_output, &vidout); - ivtv_get_audio_output(itv, 0, &audout); - IVTV_INFO("Video Output: %s\n", vidout.name); -- IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, -- audio_modes[itv->audio_stereo_mode], -- audio_modes[itv->audio_bilingual_mode]); - if (mode < 0 || mode > OUT_PASSTHROUGH) - mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); -@@ -1566,12 +1563,27 @@ static int ivtv_log_status(struct file * - IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", - (long long)itv->mpg_data_received, - (long long)itv->vbi_data_inserted); -- IVTV_INFO("================== END STATUS CARD #%d ==================\n", -- itv->instance); -- - return 0; - } - -+static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) -+{ -+ struct ivtv_open_id *id = fh2id(file->private_data); -+ struct ivtv *itv = id->itv; -+ -+ IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd); -+ return ivtv_video_command(itv, id, dec, false); -+} -+ -+static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) -+{ -+ struct ivtv_open_id *id = fh2id(file->private_data); -+ struct ivtv *itv = id->itv; -+ -+ IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd); -+ return ivtv_video_command(itv, id, dec, true); -+} -+ - static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) - { - struct ivtv_open_id *id = fh2id(filp->private_data); -@@ -1605,9 +1617,15 @@ static int ivtv_decoder_ioctls(struct fi - return ivtv_yuv_prep_frame(itv, args); - } - -+ case IVTV_IOC_PASSTHROUGH_MODE: -+ IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n"); -+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) -+ return -EINVAL; -+ return ivtv_passthrough_mode(itv, *(int *)arg != 0); -+ - case VIDEO_GET_PTS: { -- u32 data[CX2341X_MBOX_MAX_DATA]; -- u64 *pts = arg; -+ s64 *pts = arg; -+ s64 frame; - - IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); - if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { -@@ -1616,29 +1634,12 @@ static int ivtv_decoder_ioctls(struct fi - } - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; -- -- if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { -- *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) | -- (u64)itv->last_dec_timing[1]; -- break; -- } -- *pts = 0; -- if (atomic_read(&itv->decoding)) { -- if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { -- IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); -- return -EIO; -- } -- memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); -- set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); -- *pts = (u64) ((u64) data[2] << 32) | (u64) data[1]; -- /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ -- } -- break; -+ return ivtv_g_pts_frame(itv, pts, &frame); - } - - case VIDEO_GET_FRAME_COUNT: { -- u32 data[CX2341X_MBOX_MAX_DATA]; -- u64 *frame = arg; -+ s64 *frame = arg; -+ s64 pts; - - IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); - if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { -@@ -1647,71 +1648,58 @@ static int ivtv_decoder_ioctls(struct fi - } - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return -EINVAL; -- -- if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { -- *frame = itv->last_dec_timing[0]; -- break; -- } -- *frame = 0; -- if (atomic_read(&itv->decoding)) { -- if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { -- IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); -- return -EIO; -- } -- memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); -- set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); -- *frame = data[0]; -- } -- break; -+ return ivtv_g_pts_frame(itv, &pts, frame); - } - - case VIDEO_PLAY: { -- struct video_command vc; -+ struct v4l2_decoder_cmd dc; - - IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); -- memset(&vc, 0, sizeof(vc)); -- vc.cmd = VIDEO_CMD_PLAY; -- return ivtv_video_command(itv, id, &vc, 0); -+ memset(&dc, 0, sizeof(dc)); -+ dc.cmd = V4L2_DEC_CMD_START; -+ return ivtv_video_command(itv, id, &dc, 0); - } - - case VIDEO_STOP: { -- struct video_command vc; -+ struct v4l2_decoder_cmd dc; - - IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); -- memset(&vc, 0, sizeof(vc)); -- vc.cmd = VIDEO_CMD_STOP; -- vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY; -- return ivtv_video_command(itv, id, &vc, 0); -+ memset(&dc, 0, sizeof(dc)); -+ dc.cmd = V4L2_DEC_CMD_STOP; -+ dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY; -+ return ivtv_video_command(itv, id, &dc, 0); - } - - case VIDEO_FREEZE: { -- struct video_command vc; -+ struct v4l2_decoder_cmd dc; - - IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); -- memset(&vc, 0, sizeof(vc)); -- vc.cmd = VIDEO_CMD_FREEZE; -- return ivtv_video_command(itv, id, &vc, 0); -+ memset(&dc, 0, sizeof(dc)); -+ dc.cmd = V4L2_DEC_CMD_PAUSE; -+ return ivtv_video_command(itv, id, &dc, 0); - } - - case VIDEO_CONTINUE: { -- struct video_command vc; -+ struct v4l2_decoder_cmd dc; - - IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); -- memset(&vc, 0, sizeof(vc)); -- vc.cmd = VIDEO_CMD_CONTINUE; -- return ivtv_video_command(itv, id, &vc, 0); -+ memset(&dc, 0, sizeof(dc)); -+ dc.cmd = V4L2_DEC_CMD_RESUME; -+ return ivtv_video_command(itv, id, &dc, 0); - } - - case VIDEO_COMMAND: - case VIDEO_TRY_COMMAND: { -- struct video_command *vc = arg; -+ /* Note: struct v4l2_decoder_cmd has the same layout as -+ struct video_command */ -+ struct v4l2_decoder_cmd *dc = arg; - int try = (cmd == VIDEO_TRY_COMMAND); - - if (try) -- IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); -+ IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd); - else -- IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); -- return ivtv_video_command(itv, id, vc, try); -+ IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd); -+ return ivtv_video_command(itv, id, dc, try); - } - - case VIDEO_GET_EVENT: { -@@ -1775,17 +1763,13 @@ static int ivtv_decoder_ioctls(struct fi - IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); - if (iarg > AUDIO_STEREO_SWAPPED) - return -EINVAL; -- itv->audio_stereo_mode = iarg; -- ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); -- return 0; -+ return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1); - - case AUDIO_BILINGUAL_CHANNEL_SELECT: - IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); - if (iarg > AUDIO_STEREO_SWAPPED) - return -EINVAL; -- itv->audio_bilingual_mode = iarg; -- ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); -- return 0; -+ return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1); - - default: - return -EINVAL; -@@ -1800,6 +1784,7 @@ static long ivtv_default(struct file *fi - - if (!valid_prio) { - switch (cmd) { -+ case IVTV_IOC_PASSTHROUGH_MODE: - case VIDEO_PLAY: - case VIDEO_STOP: - case VIDEO_FREEZE: -@@ -1825,6 +1810,7 @@ static long ivtv_default(struct file *fi - } - - case IVTV_IOC_DMA_FRAME: -+ case IVTV_IOC_PASSTHROUGH_MODE: - case VIDEO_GET_PTS: - case VIDEO_GET_FRAME_COUNT: - case VIDEO_GET_EVENT: -@@ -1889,6 +1875,8 @@ static const struct v4l2_ioctl_ops ivtv_ - .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, - .vidioc_encoder_cmd = ivtv_encoder_cmd, - .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, -+ .vidioc_decoder_cmd = ivtv_decoder_cmd, -+ .vidioc_try_decoder_cmd = ivtv_try_decoder_cmd, - .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, - .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-streams.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-streams.c -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-streams.c -@@ -78,60 +78,73 @@ static struct { - int num_offset; - int dma, pio; - enum v4l2_buf_type buf_type; -+ u32 v4l2_caps; - const struct v4l2_file_operations *fops; - } ivtv_stream_info[] = { - { /* IVTV_ENC_STREAM_TYPE_MPG */ - "encoder MPG", - VFL_TYPE_GRABBER, 0, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, -+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | -+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_YUV */ - "encoder YUV", - VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, -+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | -+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_VBI */ - "encoder VBI", - VFL_TYPE_VBI, 0, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, -+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER | -+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_PCM */ - "encoder PCM", - VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, - PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, -+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_ENC_STREAM_TYPE_RAD */ - "encoder radio", - VFL_TYPE_RADIO, 0, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, -+ V4L2_CAP_RADIO | V4L2_CAP_TUNER, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_DEC_STREAM_TYPE_MPG */ - "decoder MPG", - VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, - PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, -+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, - &ivtv_v4l2_dec_fops - }, - { /* IVTV_DEC_STREAM_TYPE_VBI */ - "decoder VBI", - VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, -+ V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE, - &ivtv_v4l2_enc_fops - }, - { /* IVTV_DEC_STREAM_TYPE_VOUT */ - "decoder VOUT", - VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, - PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, -+ V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, - &ivtv_v4l2_dec_fops - }, - { /* IVTV_DEC_STREAM_TYPE_YUV */ - "decoder YUV", - VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, - PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, -+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, - &ivtv_v4l2_dec_fops - } - }; -@@ -149,6 +162,7 @@ static void ivtv_stream_init(struct ivtv - s->itv = itv; - s->type = type; - s->name = ivtv_stream_info[type].name; -+ s->caps = ivtv_stream_info[type].v4l2_caps; - - if (ivtv_stream_info[type].pio) - s->dma = PCI_DMA_NONE; -@@ -209,8 +223,8 @@ static int ivtv_prep_dev(struct ivtv *it - - s->vdev->num = num; - s->vdev->v4l2_dev = &itv->v4l2_dev; -- s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; - s->vdev->fops = ivtv_stream_info[type].fops; -+ s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; - s->vdev->release = video_device_release; - s->vdev->tvnorms = V4L2_STD_ALL; - s->vdev->lock = &itv->serialize_lock; -@@ -891,7 +905,7 @@ int ivtv_stop_v4l2_decode_stream(struct - IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags); - - /* Stop Decoder */ -- if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) { -+ if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) { - u32 tmp = 0; - - /* Wait until the decoder is no longer running */ -@@ -911,7 +925,7 @@ int ivtv_stop_v4l2_decode_stream(struct - break; - } - } -- ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0); -+ ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0); - - /* turn off notification of dual/stereo mode change */ - ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/it913x.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/it913x.c -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/it913x.c -@@ -64,6 +64,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr - struct it913x_state { - u8 id; - struct ite_config it913x_config; -+ u8 pid_filter_onoff; - }; - - struct ite_config it913x_config; -@@ -237,12 +238,27 @@ static int it913x_read_reg(struct usb_de - - static u32 it913x_query(struct usb_device *udev, u8 pro) - { -- int ret; -+ int ret, i; - u8 data[4]; -- ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, -- 0x1222, 0, &data[0], 3); -+ u8 ver; -+ -+ for (i = 0; i < 5; i++) { -+ ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, -+ 0x1222, 0, &data[0], 3); -+ ver = data[0]; -+ if (ver > 0 && ver < 3) -+ break; -+ msleep(100); -+ } - -- it913x_config.chip_ver = data[0]; -+ if (ver < 1 || ver > 2) { -+ info("Failed to identify chip version applying 1"); -+ it913x_config.chip_ver = 0x1; -+ it913x_config.chip_type = 0x9135; -+ return 0; -+ } -+ -+ it913x_config.chip_ver = ver; - it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; - - info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver, -@@ -259,15 +275,16 @@ static u32 it913x_query(struct usb_devic - - static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) - { -+ struct it913x_state *st = adap->dev->priv; - struct usb_device *udev = adap->dev->udev; - int ret; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - -- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) -- return -EAGAIN; -+ mutex_lock(&adap->dev->i2c_mutex); -+ - deb_info(1, "PID_C (%02x)", onoff); - -- ret = it913x_wr_reg(udev, pro, PID_EN, onoff); -+ ret = it913x_wr_reg(udev, pro, PID_EN, st->pid_filter_onoff); - - mutex_unlock(&adap->dev->i2c_mutex); - return ret; -@@ -276,12 +293,13 @@ static int it913x_pid_filter_ctrl(struct - static int it913x_pid_filter(struct dvb_usb_adapter *adap, - int index, u16 pid, int onoff) - { -+ struct it913x_state *st = adap->dev->priv; - struct usb_device *udev = adap->dev->udev; - int ret; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - -- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) -- return -EAGAIN; -+ mutex_lock(&adap->dev->i2c_mutex); -+ - deb_info(1, "PID_F (%02x)", onoff); - - ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); -@@ -292,6 +310,13 @@ static int it913x_pid_filter(struct dvb_ - - ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); - -+ if (udev->speed == USB_SPEED_HIGH && pid == 0x2000) { -+ ret |= it913x_wr_reg(udev, pro, PID_EN, !onoff); -+ st->pid_filter_onoff = !onoff; -+ } else -+ st->pid_filter_onoff = -+ adap->fe_adap[adap->active_fe].pid_filtering; -+ - mutex_unlock(&adap->dev->i2c_mutex); - return 0; - } -@@ -316,8 +341,8 @@ static int it913x_i2c_xfer(struct i2c_ad - int ret; - u32 reg; - u8 pro; -- if (mutex_lock_interruptible(&d->i2c_mutex) < 0) -- return -EAGAIN; -+ -+ mutex_lock(&d->i2c_mutex); - - debug_data_snipet(1, "Message out", msg[0].buf); - deb_info(2, "num of messages %d address %02x", num, msg[0].addr); -@@ -358,8 +383,7 @@ static int it913x_rc_query(struct dvb_us - int ret; - u32 key; - /* Avoid conflict with frontends*/ -- if (mutex_lock_interruptible(&d->i2c_mutex) < 0) -- return -EAGAIN; -+ mutex_lock(&d->i2c_mutex); - - ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET, - 0, 0, &ibuf[0], sizeof(ibuf)); -@@ -388,19 +412,12 @@ static int ite_firmware_select(struct us - { - int sw; - /* auto switch */ -- if (le16_to_cpu(udev->descriptor.idProduct) == -- USB_PID_ITETECH_IT9135) -- sw = IT9135_V1_FW; -- else if (le16_to_cpu(udev->descriptor.idProduct) == -- USB_PID_ITETECH_IT9135_9005) -+ if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_KWORLD_2) -+ sw = IT9137_FW; -+ else if (it913x_config.chip_ver == 1) - sw = IT9135_V1_FW; -- else if (le16_to_cpu(udev->descriptor.idProduct) == -- USB_PID_ITETECH_IT9135_9006) { -+ else - sw = IT9135_V2_FW; -- if (it913x_config.tuner_id_0 == 0) -- it913x_config.tuner_id_0 = IT9135_60; -- } else -- sw = IT9137_FW; - - /* force switch */ - if (dvb_usb_it913x_firmware != IT9135_AUTO) -@@ -410,41 +427,103 @@ static int ite_firmware_select(struct us - case IT9135_V1_FW: - it913x_config.firmware_ver = 1; - it913x_config.adc_x2 = 1; -+ it913x_config.read_slevel = false; - props->firmware = fw_it9135_v1; - break; - case IT9135_V2_FW: - it913x_config.firmware_ver = 1; - it913x_config.adc_x2 = 1; -+ it913x_config.read_slevel = false; - props->firmware = fw_it9135_v2; -+ switch (it913x_config.tuner_id_0) { -+ case IT9135_61: -+ case IT9135_62: -+ break; -+ default: -+ info("Unknown tuner ID applying default 0x60"); -+ case IT9135_60: -+ it913x_config.tuner_id_0 = IT9135_60; -+ } - break; - case IT9137_FW: - default: - it913x_config.firmware_ver = 0; - it913x_config.adc_x2 = 0; -+ it913x_config.read_slevel = true; - props->firmware = fw_it9137; - } - - return 0; - } - -+static void it913x_select_remote(struct usb_device *udev, -+ struct dvb_usb_device_properties *props) -+{ -+ switch (le16_to_cpu(udev->descriptor.idProduct)) { -+ case USB_PID_ITETECH_IT9135_9005: -+ props->rc.core.rc_codes = RC_MAP_IT913X_V2; -+ return; -+ default: -+ props->rc.core.rc_codes = RC_MAP_IT913X_V1; -+ } -+ return; -+} -+ - #define TS_MPEG_PKT_SIZE 188 - #define EP_LOW 21 - #define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) - #define EP_HIGH 348 - #define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) - --static int it913x_identify_state(struct usb_device *udev, -- struct dvb_usb_device_properties *props, -- struct dvb_usb_device_description **desc, -- int *cold) -+static int it913x_select_config(struct usb_device *udev, -+ struct dvb_usb_device_properties *props) - { -- int ret = 0, firm_no; -- u8 reg, remote; -+ int ret = 0, reg; -+ bool proprietary_ir = false; - -- firm_no = it913x_return_status(udev); -+ if (it913x_config.chip_ver == 0x02 -+ && it913x_config.chip_type == 0x9135) -+ reg = it913x_read_reg(udev, 0x461d); -+ else -+ reg = it913x_read_reg(udev, 0x461b); - -- /* checnk for dual mode */ -- it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); -+ if (reg < 0) -+ return reg; -+ -+ if (reg == 0) { -+ it913x_config.dual_mode = 0; -+ it913x_config.tuner_id_0 = IT9135_38; -+ proprietary_ir = true; -+ } else { -+ /* TS mode */ -+ reg = it913x_read_reg(udev, 0x49c5); -+ if (reg < 0) -+ return reg; -+ it913x_config.dual_mode = reg; -+ -+ /* IR mode type */ -+ reg = it913x_read_reg(udev, 0x49ac); -+ if (reg < 0) -+ return reg; -+ if (reg == 5) { -+ info("Remote propriety (raw) mode"); -+ proprietary_ir = true; -+ } else if (reg == 1) { -+ info("Remote HID mode NOT SUPPORTED"); -+ proprietary_ir = false; -+ props->rc.core.rc_codes = NULL; -+ } else -+ props->rc.core.rc_codes = NULL; -+ -+ /* Tuner_id */ -+ reg = it913x_read_reg(udev, 0x49d0); -+ if (reg < 0) -+ return reg; -+ it913x_config.tuner_id_0 = reg; -+ } -+ -+ if (proprietary_ir) -+ it913x_select_remote(udev, props); - - if (udev->speed != USB_SPEED_HIGH) { - props->adapter[0].fe[0].pid_filter_count = 5; -@@ -459,17 +538,6 @@ static int it913x_identify_state(struct - if(props->adapter[0].fe[0].pid_filter_count == 5) - props->adapter[0].fe[0].pid_filter_count = 31; - -- /* TODO different remotes */ -- remote = it913x_read_reg(udev, 0x49ac); /* Remote */ -- if (remote == 0) -- props->rc.core.rc_codes = NULL; -- -- /* TODO at the moment tuner_id is always assigned to 0x38 */ -- it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0); -- -- info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode -- , remote, it913x_config.tuner_id_0); -- - /* Select Stream Buffer Size and pid filter option*/ - if (pid_filter) { - props->adapter[0].fe[0].stream.u.bulk.buffersize = -@@ -490,8 +558,29 @@ static int it913x_identify_state(struct - } else - props->num_adapters = 1; - -+ info("Dual mode=%x Tuner Type=%x", it913x_config.dual_mode, -+ it913x_config.tuner_id_0); -+ - ret = ite_firmware_select(udev, props); - -+ return ret; -+} -+ -+static int it913x_identify_state(struct usb_device *udev, -+ struct dvb_usb_device_properties *props, -+ struct dvb_usb_device_description **desc, -+ int *cold) -+{ -+ int ret = 0, firm_no; -+ u8 reg; -+ -+ firm_no = it913x_return_status(udev); -+ -+ /* Read and select config */ -+ ret = it913x_select_config(udev, props); -+ if (ret < 0) -+ return ret; -+ - if (firm_no > 0) { - *cold = 0; - return 0; -@@ -538,18 +627,22 @@ static int it913x_identify_state(struct - - static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) - { -+ struct it913x_state *st = adap->dev->priv; - int ret = 0; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - -- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) -- return -EAGAIN; - deb_info(1, "STM (%02x)", onoff); - -- if (!onoff) -+ if (!onoff) { -+ mutex_lock(&adap->dev->i2c_mutex); -+ - ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1); - -+ mutex_unlock(&adap->dev->i2c_mutex); -+ st->pid_filter_onoff = -+ adap->fe_adap[adap->active_fe].pid_filtering; - -- mutex_unlock(&adap->dev->i2c_mutex); -+ } - - return ret; - } -@@ -582,30 +675,41 @@ static int it913x_download_firmware(stru - if ((packet_size > min_pkt) || (i == fw->size)) { - fw_data = (u8 *)(fw->data + pos); - pos += packet_size; -- if (packet_size > 0) -- ret |= it913x_io(udev, WRITE_DATA, -+ if (packet_size > 0) { -+ ret = it913x_io(udev, WRITE_DATA, - DEV_0, CMD_SCATTER_WRITE, 0, - 0, fw_data, packet_size); -+ if (ret < 0) -+ break; -+ } - udelay(1000); - } - } - i++; - } - -- ret |= it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); -- -- msleep(100); -- - if (ret < 0) -- info("FRM Firmware Download Failed (%04x)" , ret); -+ info("FRM Firmware Download Failed (%d)" , ret); - else - info("FRM Firmware Download Completed - Resetting Device"); - -- ret |= it913x_return_status(udev); -+ msleep(30); -+ -+ ret = it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); -+ if (ret < 0) -+ info("FRM Device not responding to reboot"); -+ -+ ret = it913x_return_status(udev); -+ if (ret == 0) { -+ info("FRM Failed to reboot device"); -+ return -ENODEV; -+ } - - msleep(30); - -- ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); -+ ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); -+ -+ msleep(30); - - /* Tuner function */ - if (it913x_config.dual_mode) -@@ -789,7 +893,7 @@ static struct dvb_usb_device_properties - .rc_query = it913x_rc_query, - .rc_interval = IT913X_POLL, - .allowed_protos = RC_TYPE_NEC, -- .rc_codes = RC_MAP_MSI_DIGIVOX_III, -+ .rc_codes = RC_MAP_IT913X_V1, - }, - .i2c_algo = &it913x_i2c_algo, - .num_device_descs = 5, -@@ -823,5 +927,5 @@ module_usb_driver(it913x_driver); - - MODULE_AUTHOR("Malcolm Priestley "); - MODULE_DESCRIPTION("it913x USB 2 Driver"); --MODULE_VERSION("1.22"); -+MODULE_VERSION("1.28"); - MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/base/driver.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/base/driver.c -+++ linux-3.3.x86_64/drivers/base/driver.c -@@ -234,7 +234,6 @@ int driver_register(struct device_driver - - other = driver_find(drv->name, drv->bus); - if (other) { -- put_driver(other); - printk(KERN_ERR "Error: Driver '%s' is already registered, " - "aborting...\n", drv->name); - return -EBUSY; -@@ -275,7 +274,9 @@ EXPORT_SYMBOL_GPL(driver_unregister); - * Call kset_find_obj() to iterate over list of drivers on - * a bus to find driver by name. Return driver if found. - * -- * Note that kset_find_obj increments driver's reference count. -+ * This routine provides no locking to prevent the driver it returns -+ * from being unregistered or unloaded while the caller is using it. -+ * The caller is responsible for preventing this. - */ - struct device_driver *driver_find(const char *name, struct bus_type *bus) - { -@@ -283,6 +284,8 @@ struct device_driver *driver_find(const - struct driver_private *priv; - - if (k) { -+ /* Drop reference added by kset_find_obj() */ -+ kobject_put(k); - priv = to_driver(k); - return priv->driver; - } -Index: linux-3.3.x86_64/drivers/input/gameport/gameport.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/input/gameport/gameport.c -+++ linux-3.3.x86_64/drivers/input/gameport/gameport.c -@@ -449,7 +449,6 @@ static ssize_t gameport_rebind_driver(st - } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) { - gameport_disconnect_port(gameport); - error = gameport_bind_driver(gameport, to_gameport_driver(drv)); -- put_driver(drv); - } else { - error = -EINVAL; - } -Index: linux-3.3.x86_64/drivers/input/serio/serio.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/input/serio/serio.c -+++ linux-3.3.x86_64/drivers/input/serio/serio.c -@@ -441,7 +441,6 @@ static ssize_t serio_rebind_driver(struc - } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { - serio_disconnect_port(serio); - error = serio_bind_driver(serio, to_serio_driver(drv)); -- put_driver(drv); - serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); - } else { - error = -EINVAL; -Index: linux-3.3.x86_64/drivers/media/video/cx18/cx18-alsa-main.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx18/cx18-alsa-main.c -+++ linux-3.3.x86_64/drivers/media/video/cx18/cx18-alsa-main.c -@@ -285,7 +285,6 @@ static void __exit cx18_alsa_exit(void) - - drv = driver_find("cx18", &pci_bus_type); - ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback); -- put_driver(drv); - - cx18_ext_init = NULL; - printk(KERN_INFO "cx18-alsa: module unload complete\n"); -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtvfb.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtvfb.c -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtvfb.c -@@ -1293,7 +1293,6 @@ static int __init ivtvfb_init(void) - - drv = driver_find("ivtv", &pci_bus_type); - err = driver_for_each_device(drv, NULL, ®istered, ivtvfb_callback_init); -- put_driver(drv); - if (!registered) { - printk(KERN_ERR "ivtvfb: no cards found\n"); - return -ENODEV; -@@ -1310,7 +1309,6 @@ static void ivtvfb_cleanup(void) - - drv = driver_find("ivtv", &pci_bus_type); - err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup); -- put_driver(drv); - } - - module_init(ivtvfb_init); -Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-mdevice.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/fimc-mdevice.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-mdevice.c -@@ -344,16 +344,13 @@ static int fimc_md_register_platform_ent - return -ENODEV; - ret = driver_for_each_device(driver, NULL, fmd, - fimc_register_callback); -- put_driver(driver); - if (ret) - return ret; - - driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type); -- if (driver) { -+ if (driver) - ret = driver_for_each_device(driver, NULL, fmd, - csis_register_callback); -- put_driver(driver); -- } - return ret; - } - -@@ -753,7 +750,7 @@ static int __devinit fimc_md_probe(struc - struct fimc_md *fmd; - int ret; - -- fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL); -+ fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL); - if (!fmd) - return -ENOMEM; - -@@ -774,7 +771,7 @@ static int __devinit fimc_md_probe(struc - ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); -- goto err1; -+ return ret; - } - ret = media_device_register(&fmd->media_dev); - if (ret < 0) { -@@ -816,8 +813,6 @@ err3: - fimc_md_unregister_entities(fmd); - err2: - v4l2_device_unregister(&fmd->v4l2_dev); --err1: -- kfree(fmd); - return ret; - } - -@@ -831,7 +826,6 @@ static int __devexit fimc_md_remove(stru - fimc_md_unregister_entities(fmd); - media_device_unregister(&fmd->media_dev); - fimc_md_put_clocks(fmd); -- kfree(fmd); - return 0; - } - -Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/mixer_video.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/mixer_video.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-tv/mixer_video.c -@@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_regi - } - - done: -- put_driver(drv); - return sd; - } - -Index: linux-3.3.x86_64/drivers/s390/net/smsgiucv_app.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/s390/net/smsgiucv_app.c -+++ linux-3.3.x86_64/drivers/s390/net/smsgiucv_app.c -@@ -168,7 +168,7 @@ static int __init smsgiucv_app_init(void - rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT); - if (rc) { - kfree(smsg_app_dev); -- goto fail_put_driver; -+ goto fail; - } - smsg_app_dev->bus = &iucv_bus; - smsg_app_dev->parent = iucv_root; -@@ -177,7 +177,7 @@ static int __init smsgiucv_app_init(void - rc = device_register(smsg_app_dev); - if (rc) { - put_device(smsg_app_dev); -- goto fail_put_driver; -+ goto fail; - } - - /* convert sender to uppercase characters */ -@@ -191,12 +191,11 @@ static int __init smsgiucv_app_init(void - rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback); - if (rc) { - device_unregister(smsg_app_dev); -- goto fail_put_driver; -+ goto fail; - } - - rc = 0; --fail_put_driver: -- put_driver(smsgiucv_drv); -+fail: - return rc; - } - module_init(smsgiucv_app_init); -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/anysee.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/anysee.c -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/anysee.c -@@ -58,7 +58,7 @@ static int anysee_ctrl_msg(struct dvb_us - u8 *rbuf, u8 rlen) - { - struct anysee_state *state = d->priv; -- int act_len, ret; -+ int act_len, ret, i; - u8 buf[64]; - - memcpy(&buf[0], sbuf, slen); -@@ -73,26 +73,52 @@ static int anysee_ctrl_msg(struct dvb_us - /* We need receive one message more after dvb_usb_generic_rw due - to weird transaction flow, which is 1 x send + 2 x receive. */ - ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); -- if (!ret) { -+ if (ret) -+ goto error_unlock; -+ -+ /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 -+ * (EPIPE, Broken pipe). Function supports currently msleep() as a -+ * parameter but I would not like to use it, since according to -+ * Documentation/timers/timers-howto.txt it should not be used such -+ * short, under < 20ms, sleeps. Repeating failed message would be -+ * better choice as not to add unwanted delays... -+ * Fixing that correctly is one of those or both; -+ * 1) use repeat if possible -+ * 2) add suitable delay -+ */ -+ -+ /* get answer, retry few times if error returned */ -+ for (i = 0; i < 3; i++) { - /* receive 2nd answer */ - ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf), - &act_len, 2000); -- if (ret) -- err("%s: recv bulk message failed: %d", __func__, ret); -- else { -+ -+ if (ret) { -+ deb_info("%s: recv bulk message failed: %d", -+ __func__, ret); -+ } else { - deb_xfer("<<< "); - debug_dump(buf, rlen, deb_xfer); - - if (buf[63] != 0x4f) - deb_info("%s: cmd failed\n", __func__); -+ -+ break; - } - } - -+ if (ret) { -+ /* all retries failed, it is fatal */ -+ err("%s: recv bulk message failed: %d", __func__, ret); -+ goto error_unlock; -+ } -+ - /* read request, copy returned data to return buf */ -- if (!ret && rbuf && rlen) -+ if (rbuf && rlen) - memcpy(rbuf, buf, rlen); - -+error_unlock: - mutex_unlock(&anysee_usb_mutex); - - return ret; -Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/hdmi_drv.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/hdmi_drv.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-tv/hdmi_drv.c -@@ -30,6 +30,7 @@ - #include - #include - -+#include - #include - #include - #include -@@ -66,6 +67,8 @@ struct hdmi_device { - struct v4l2_device v4l2_dev; - /** subdev of HDMIPHY interface */ - struct v4l2_subdev *phy_sd; -+ /** subdev of MHL interface */ -+ struct v4l2_subdev *mhl_sd; - /** configuration of current graphic mode */ - const struct hdmi_preset_conf *cur_conf; - /** current preset */ -@@ -74,10 +77,6 @@ struct hdmi_device { - struct hdmi_resources res; - }; - --struct hdmi_driver_data { -- int hdmiphy_bus; --}; -- - struct hdmi_tg_regs { - u8 cmd; - u8 h_fsz_l; -@@ -129,23 +128,11 @@ struct hdmi_preset_conf { - struct v4l2_mbus_framefmt mbus_fmt; - }; - --/* I2C module and id for HDMIPHY */ --static struct i2c_board_info hdmiphy_info = { -- I2C_BOARD_INFO("hdmiphy", 0x38), --}; -- --static struct hdmi_driver_data hdmi_driver_data[] = { -- { .hdmiphy_bus = 3 }, -- { .hdmiphy_bus = 8 }, --}; -- - static struct platform_device_id hdmi_driver_types[] = { - { - .name = "s5pv210-hdmi", -- .driver_data = (unsigned long)&hdmi_driver_data[0], - }, { - .name = "exynos4-hdmi", -- .driver_data = (unsigned long)&hdmi_driver_data[1], - }, { - /* end node */ - } -@@ -587,7 +574,15 @@ static int hdmi_streamon(struct hdmi_dev - if (tries == 0) { - dev_err(dev, "hdmiphy's pll could not reach steady state.\n"); - v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); -- hdmi_dumpregs(hdev, "s_stream"); -+ hdmi_dumpregs(hdev, "hdmiphy - s_stream"); -+ return -EIO; -+ } -+ -+ /* starting MHL */ -+ ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1); -+ if (hdev->mhl_sd && ret) { -+ v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); -+ hdmi_dumpregs(hdev, "mhl - s_stream"); - return -EIO; - } - -@@ -618,6 +613,7 @@ static int hdmi_streamoff(struct hdmi_de - clk_set_parent(res->sclk_hdmi, res->sclk_pixel); - clk_enable(res->sclk_hdmi); - -+ v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0); - v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0); - - hdmi_dumpregs(hdev, "streamoff"); -@@ -739,6 +735,7 @@ static int hdmi_runtime_suspend(struct d - struct hdmi_device *hdev = sd_to_hdmi_dev(sd); - - dev_dbg(dev, "%s\n", __func__); -+ v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0); - hdmi_resource_poweroff(&hdev->res); - return 0; - } -@@ -757,6 +754,11 @@ static int hdmi_runtime_resume(struct de - if (ret) - goto fail; - -+ /* starting MHL */ -+ ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1); -+ if (hdev->mhl_sd && ret) -+ goto fail; -+ - dev_dbg(dev, "poweron succeed\n"); - - return 0; -@@ -867,15 +869,21 @@ static int __devinit hdmi_probe(struct p - { - struct device *dev = &pdev->dev; - struct resource *res; -- struct i2c_adapter *phy_adapter; -+ struct i2c_adapter *adapter; - struct v4l2_subdev *sd; - struct hdmi_device *hdmi_dev = NULL; -- struct hdmi_driver_data *drv_data; -+ struct s5p_hdmi_platform_data *pdata = dev->platform_data; - int ret; - - dev_dbg(dev, "probe start\n"); - -- hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL); -+ if (!pdata) { -+ dev_err(dev, "platform data is missing\n"); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL); - if (!hdmi_dev) { - dev_err(dev, "out of memory\n"); - ret = -ENOMEM; -@@ -886,7 +894,7 @@ static int __devinit hdmi_probe(struct p - - ret = hdmi_resources_init(hdmi_dev); - if (ret) -- goto fail_hdev; -+ goto fail; - - /* mapping HDMI registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -@@ -896,24 +904,26 @@ static int __devinit hdmi_probe(struct p - goto fail_init; - } - -- hdmi_dev->regs = ioremap(res->start, resource_size(res)); -+ hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start, -+ resource_size(res)); - if (hdmi_dev->regs == NULL) { - dev_err(dev, "register mapping failed.\n"); - ret = -ENXIO; -- goto fail_hdev; -+ goto fail_init; - } - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(dev, "get interrupt resource failed.\n"); - ret = -ENXIO; -- goto fail_regs; -+ goto fail_init; - } - -- ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev); -+ ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0, -+ "hdmi", hdmi_dev); - if (ret) { - dev_err(dev, "request interrupt failed.\n"); -- goto fail_regs; -+ goto fail_init; - } - hdmi_dev->irq = res->start; - -@@ -924,28 +934,54 @@ static int __devinit hdmi_probe(struct p - ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev); - if (ret) { - dev_err(dev, "could not register v4l2 device.\n"); -- goto fail_irq; -+ goto fail_init; - } - -- drv_data = (struct hdmi_driver_data *) -- platform_get_device_id(pdev)->driver_data; -- phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus); -- if (phy_adapter == NULL) { -- dev_err(dev, "adapter request failed\n"); -+ /* testing if hdmiphy info is present */ -+ if (!pdata->hdmiphy_info) { -+ dev_err(dev, "hdmiphy info is missing in platform data\n"); -+ ret = -ENXIO; -+ goto fail_vdev; -+ } -+ -+ adapter = i2c_get_adapter(pdata->hdmiphy_bus); -+ if (adapter == NULL) { -+ dev_err(dev, "hdmiphy adapter request failed\n"); - ret = -ENXIO; - goto fail_vdev; - } - - hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev, -- phy_adapter, &hdmiphy_info, NULL); -+ adapter, pdata->hdmiphy_info, NULL); - /* on failure or not adapter is no longer useful */ -- i2c_put_adapter(phy_adapter); -+ i2c_put_adapter(adapter); - if (hdmi_dev->phy_sd == NULL) { - dev_err(dev, "missing subdev for hdmiphy\n"); - ret = -ENODEV; - goto fail_vdev; - } - -+ /* initialization of MHL interface if present */ -+ if (pdata->mhl_info) { -+ adapter = i2c_get_adapter(pdata->mhl_bus); -+ if (adapter == NULL) { -+ dev_err(dev, "MHL adapter request failed\n"); -+ ret = -ENXIO; -+ goto fail_vdev; -+ } -+ -+ hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board( -+ &hdmi_dev->v4l2_dev, adapter, -+ pdata->mhl_info, NULL); -+ /* on failure or not adapter is no longer useful */ -+ i2c_put_adapter(adapter); -+ if (hdmi_dev->mhl_sd == NULL) { -+ dev_err(dev, "missing subdev for MHL\n"); -+ ret = -ENODEV; -+ goto fail_vdev; -+ } -+ } -+ - clk_enable(hdmi_dev->res.hdmi); - - pm_runtime_enable(dev); -@@ -969,18 +1005,9 @@ static int __devinit hdmi_probe(struct p - fail_vdev: - v4l2_device_unregister(&hdmi_dev->v4l2_dev); - --fail_irq: -- free_irq(hdmi_dev->irq, hdmi_dev); -- --fail_regs: -- iounmap(hdmi_dev->regs); -- - fail_init: - hdmi_resources_cleanup(hdmi_dev); - --fail_hdev: -- kfree(hdmi_dev); -- - fail: - dev_err(dev, "probe failed\n"); - return ret; -@@ -996,8 +1023,6 @@ static int __devexit hdmi_remove(struct - clk_disable(hdmi_dev->res.hdmi); - v4l2_device_unregister(&hdmi_dev->v4l2_dev); - disable_irq(hdmi_dev->irq); -- free_irq(hdmi_dev->irq, hdmi_dev); -- iounmap(hdmi_dev->regs); - hdmi_resources_cleanup(hdmi_dev); - kfree(hdmi_dev); - dev_info(dev, "remove sucessful\n"); -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/lmedm04.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/lmedm04.c -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/lmedm04.c -@@ -77,6 +77,7 @@ - #include "stv0299.h" - #include "dvb-pll.h" - #include "z0194a.h" -+#include "m88rs2000.h" - - - -@@ -104,7 +105,7 @@ MODULE_PARM_DESC(firmware, "set default - - static int pid_filter; - module_param_named(pid, pid_filter, int, 0644); --MODULE_PARM_DESC(pid, "set default 0=on 1=off"); -+MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on"); - - - DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -@@ -113,6 +114,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr - #define TUNER_LG 0x1 - #define TUNER_S7395 0x2 - #define TUNER_S0194 0x3 -+#define TUNER_RS2000 0x4 - - struct lme2510_state { - u8 id; -@@ -121,6 +123,8 @@ struct lme2510_state { - u8 signal_level; - u8 signal_sn; - u8 time_key; -+ u8 last_key; -+ u8 key_timeout; - u8 i2c_talk_onoff; - u8 i2c_gate; - u8 i2c_tuner_gate_w; -@@ -128,6 +132,7 @@ struct lme2510_state { - u8 i2c_tuner_addr; - u8 stream_on; - u8 pid_size; -+ u8 pid_off; - void *buffer; - struct urb *lme_urb; - void *usb_buffer; -@@ -178,14 +183,8 @@ static int lme2510_usb_talk(struct dvb_u - /* the read/write capped at 64 */ - memcpy(buff, wbuf, (wlen < 64) ? wlen : 64); - -- ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01)); -- - ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01); - -- msleep(10); -- -- ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01)); -- - ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ? - rlen : 64 , 0x01); - -@@ -199,9 +198,14 @@ static int lme2510_usb_talk(struct dvb_u - - static int lme2510_stream_restart(struct dvb_usb_device *d) - { -- static u8 stream_on[] = LME_ST_ON_W; -+ struct lme2510_state *st = d->priv; -+ u8 all_pids[] = LME_ALL_PIDS; -+ u8 stream_on[] = LME_ST_ON_W; - int ret; -- u8 rbuff[10]; -+ u8 rbuff[1]; -+ if (st->pid_off) -+ ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids), -+ rbuff, sizeof(rbuff)); - /*Restart Stream Command*/ - ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on), - rbuff, sizeof(rbuff)); -@@ -308,6 +312,14 @@ static void lme2510_int_response(struct - ((ibuf[2] & 0x01) << 0x03); - } - break; -+ case TUNER_RS2000: -+ if (ibuf[2] > 0) -+ st->signal_lock = 0xff; -+ else -+ st->signal_lock = 0xf0; -+ st->signal_level = ibuf[4]; -+ st->signal_sn = ibuf[5]; -+ st->time_key = ibuf[7]; - default: - break; - } -@@ -359,19 +371,20 @@ static int lme2510_int_read(struct dvb_u - static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) - { - struct lme2510_state *st = adap->dev->priv; -- static u8 clear_pid_reg[] = LME_CLEAR_PID; -+ static u8 clear_pid_reg[] = LME_ALL_PIDS; - static u8 rbuf[1]; - int ret; - - deb_info(1, "PID Clearing Filter"); - -- ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); -- if (ret < 0) -- return -EAGAIN; -+ mutex_lock(&adap->dev->i2c_mutex); - -- if (!onoff) -+ if (!onoff) { - ret |= lme2510_usb_talk(adap->dev, clear_pid_reg, - sizeof(clear_pid_reg), rbuf, sizeof(rbuf)); -+ st->pid_off = true; -+ } else -+ st->pid_off = false; - - st->pid_size = 0; - -@@ -389,11 +402,9 @@ static int lme2510_pid_filter(struct dvb - pid, index, onoff); - - if (onoff) { -- ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); -- if (ret < 0) -- return -EAGAIN; -- ret |= lme2510_enable_pid(adap->dev, index, pid); -- mutex_unlock(&adap->dev->i2c_mutex); -+ mutex_lock(&adap->dev->i2c_mutex); -+ ret |= lme2510_enable_pid(adap->dev, index, pid); -+ mutex_unlock(&adap->dev->i2c_mutex); - } - - -@@ -425,9 +436,6 @@ static int lme2510_msg(struct dvb_usb_de - int ret = 0; - struct lme2510_state *st = d->priv; - -- if (mutex_lock_interruptible(&d->i2c_mutex) < 0) -- return -EAGAIN; -- - if (st->i2c_talk_onoff == 1) { - - ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); -@@ -456,8 +464,6 @@ static int lme2510_msg(struct dvb_usb_de - st->i2c_talk_onoff = 0; - } - } -- if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5)) -- msleep(5); - } - break; - case TUNER_S0194: -@@ -472,10 +478,12 @@ static int lme2510_msg(struct dvb_usb_de - } - } - break; -+ case TUNER_RS2000: - default: - break; - } - } else { -+ /* TODO rewrite this section */ - switch (st->tuner_config) { - case TUNER_LG: - switch (wbuf[3]) { -@@ -559,6 +567,24 @@ static int lme2510_msg(struct dvb_usb_de - break; - } - break; -+ case TUNER_RS2000: -+ switch (wbuf[3]) { -+ case 0x8c: -+ rbuf[0] = 0x55; -+ rbuf[1] = 0xff; -+ if (st->last_key == st->time_key) { -+ st->key_timeout++; -+ if (st->key_timeout > 5) -+ rbuf[1] = 0; -+ } else -+ st->key_timeout = 0; -+ st->last_key = st->time_key; -+ break; -+ default: -+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); -+ st->i2c_talk_onoff = 1; -+ break; -+ } - default: - break; - } -@@ -568,8 +594,6 @@ static int lme2510_msg(struct dvb_usb_de - - } - -- mutex_unlock(&d->i2c_mutex); -- - return ret; - } - -@@ -584,6 +608,8 @@ static int lme2510_i2c_xfer(struct i2c_a - u16 len; - u8 gate = st->i2c_gate; - -+ mutex_lock(&d->i2c_mutex); -+ - if (gate == 0) - gate = 5; - -@@ -622,6 +648,7 @@ static int lme2510_i2c_xfer(struct i2c_a - - if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) { - deb_info(1, "i2c transfer failed."); -+ mutex_unlock(&d->i2c_mutex); - return -EAGAIN; - } - -@@ -634,6 +661,8 @@ static int lme2510_i2c_xfer(struct i2c_a - } - } - } -+ -+ mutex_unlock(&d->i2c_mutex); - return i; - } - -@@ -653,7 +682,7 @@ static int lme2510_identify_state(struct - struct dvb_usb_device_description **desc, - int *cold) - { -- if (pid_filter > 0) -+ if (pid_filter != 2) - props->adapter[0].fe[0].caps &= - ~DVB_USB_ADAP_NEED_PID_FILTERING; - *cold = 0; -@@ -663,7 +692,7 @@ static int lme2510_identify_state(struct - static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) - { - struct lme2510_state *st = adap->dev->priv; -- static u8 clear_reg_3[] = LME_CLEAR_PID; -+ static u8 clear_reg_3[] = LME_ALL_PIDS; - static u8 rbuf[1]; - int ret = 0, rlen = sizeof(rbuf); - -@@ -675,8 +704,7 @@ static int lme2510_streaming_ctrl(struct - else { - deb_info(1, "STM Steam Off"); - /* mutex is here only to avoid collision with I2C */ -- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) -- return -EAGAIN; -+ mutex_lock(&adap->dev->i2c_mutex); - - ret = lme2510_usb_talk(adap->dev, clear_reg_3, - sizeof(clear_reg_3), rbuf, rlen); -@@ -781,16 +809,18 @@ static int lme_firmware_switch(struct us - const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; - const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw"; - const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw"; -+ const char fw_c_rs2000[] = "dvb-usb-lme2510c-rs2000.fw"; - const char fw_lg[] = "dvb-usb-lme2510-lg.fw"; - const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw"; - const char *fw_lme; -- int ret, cold_fw; -+ int ret = 0, cold_fw; - - cold = (cold > 0) ? (cold & 1) : 0; - - cold_fw = !cold; - -- if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) { -+ switch (le16_to_cpu(udev->descriptor.idProduct)) { -+ case 0x1122: - switch (dvb_usb_lme2510_firmware) { - default: - dvb_usb_lme2510_firmware = TUNER_S0194; -@@ -813,7 +843,8 @@ static int lme_firmware_switch(struct us - cold_fw = 0; - break; - } -- } else { -+ break; -+ case 0x1120: - switch (dvb_usb_lme2510_firmware) { - default: - dvb_usb_lme2510_firmware = TUNER_S7395; -@@ -842,8 +873,17 @@ static int lme_firmware_switch(struct us - cold_fw = 0; - break; - } -+ break; -+ case 0x22f0: -+ fw_lme = fw_c_rs2000; -+ ret = request_firmware(&fw, fw_lme, &udev->dev); -+ dvb_usb_lme2510_firmware = TUNER_RS2000; -+ break; -+ default: -+ fw_lme = fw_c_s7395; - } - -+ - if (cold_fw) { - info("FRM Loading %s file", fw_lme); - ret = lme2510_download_firmware(udev, fw); -@@ -906,6 +946,29 @@ static struct stv0299_config sharp_z0194 - .set_symbol_rate = sharp_z0194a_set_symbol_rate, - }; - -+static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, -+ int caller) -+{ -+ struct dvb_usb_adapter *adap = fe->dvb->priv; -+ struct dvb_usb_device *d = adap->dev; -+ struct lme2510_state *st = d->priv; -+ -+ mutex_lock(&d->i2c_mutex); -+ if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { -+ st->i2c_talk_onoff = 0; -+ lme2510_stream_restart(d); -+ } -+ mutex_unlock(&d->i2c_mutex); -+ -+ return 0; -+} -+ -+static struct m88rs2000_config m88rs2000_config = { -+ .demod_addr = 0xd0, -+ .tuner_addr = 0xc0, -+ .set_ts_params = dm04_rs2000_set_ts_param, -+}; -+ - static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) - { -@@ -915,8 +978,7 @@ static int dm04_lme2510_set_voltage(stru - static u8 rbuf[1]; - int ret = 0, len = 3, rlen = 1; - -- if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) -- return -EAGAIN; -+ mutex_lock(&adap->dev->i2c_mutex); - - switch (voltage) { - case SEC_VOLTAGE_18: -@@ -937,12 +999,31 @@ static int dm04_lme2510_set_voltage(stru - return (ret < 0) ? -ENODEV : 0; - } - -+static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, -+ u16 *strength) -+{ -+ struct dvb_usb_adapter *adap = fe->dvb->priv; -+ struct lme2510_state *st = adap->dev->priv; -+ -+ *strength = (u16)((u32)st->signal_level * 0xffff / 0x7f); -+ return 0; -+} -+ -+static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) -+{ -+ struct dvb_usb_adapter *adap = fe->dvb->priv; -+ struct lme2510_state *st = adap->dev->priv; -+ -+ *snr = (u16)((u32)st->signal_sn * 0xffff / 0xff); -+ return 0; -+} -+ - static int lme_name(struct dvb_usb_adapter *adap) - { - struct lme2510_state *st = adap->dev->priv; - const char *desc = adap->dev->desc->name; - char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", -- " SHARP:BS2F7HZ0194"}; -+ " SHARP:BS2F7HZ0194", " RS2000"}; - char *name = adap->fe_adap[0].fe->ops.info.name; - - strlcpy(name, desc, 128); -@@ -958,60 +1039,82 @@ static int dm04_lme2510_frontend_attach( - int ret = 0; - - st->i2c_talk_onoff = 1; -+ switch (le16_to_cpu(adap->dev->udev->descriptor.idProduct)) { -+ case 0x1122: -+ case 0x1120: -+ st->i2c_gate = 4; -+ adap->fe_adap[0].fe = dvb_attach(tda10086_attach, -+ &tda10086_config, &adap->dev->i2c_adap); -+ if (adap->fe_adap[0].fe) { -+ info("TUN Found Frontend TDA10086"); -+ st->i2c_tuner_gate_w = 4; -+ st->i2c_tuner_gate_r = 4; -+ st->i2c_tuner_addr = 0xc0; -+ st->tuner_config = TUNER_LG; -+ if (dvb_usb_lme2510_firmware != TUNER_LG) { -+ dvb_usb_lme2510_firmware = TUNER_LG; -+ ret = lme_firmware_switch(adap->dev->udev, 1); -+ } -+ break; -+ } - -- st->i2c_gate = 4; -- adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, -- &adap->dev->i2c_adap); -- -- if (adap->fe_adap[0].fe) { -- info("TUN Found Frontend TDA10086"); -- st->i2c_tuner_gate_w = 4; -- st->i2c_tuner_gate_r = 4; -- st->i2c_tuner_addr = 0xc0; -- st->tuner_config = TUNER_LG; -- if (dvb_usb_lme2510_firmware != TUNER_LG) { -- dvb_usb_lme2510_firmware = TUNER_LG; -- ret = lme_firmware_switch(adap->dev->udev, 1); -+ st->i2c_gate = 4; -+ adap->fe_adap[0].fe = dvb_attach(stv0299_attach, -+ &sharp_z0194_config, &adap->dev->i2c_adap); -+ if (adap->fe_adap[0].fe) { -+ info("FE Found Stv0299"); -+ st->i2c_tuner_gate_w = 4; -+ st->i2c_tuner_gate_r = 5; -+ st->i2c_tuner_addr = 0xc0; -+ st->tuner_config = TUNER_S0194; -+ if (dvb_usb_lme2510_firmware != TUNER_S0194) { -+ dvb_usb_lme2510_firmware = TUNER_S0194; -+ ret = lme_firmware_switch(adap->dev->udev, 1); -+ } -+ break; - } -- goto end; -- } - -- st->i2c_gate = 4; -- adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config, -+ st->i2c_gate = 5; -+ adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config, - &adap->dev->i2c_adap); -- if (adap->fe_adap[0].fe) { -- info("FE Found Stv0299"); -- st->i2c_tuner_gate_w = 4; -- st->i2c_tuner_gate_r = 5; -- st->i2c_tuner_addr = 0xc0; -- st->tuner_config = TUNER_S0194; -- if (dvb_usb_lme2510_firmware != TUNER_S0194) { -- dvb_usb_lme2510_firmware = TUNER_S0194; -- ret = lme_firmware_switch(adap->dev->udev, 1); -+ -+ if (adap->fe_adap[0].fe) { -+ info("FE Found Stv0288"); -+ st->i2c_tuner_gate_w = 4; -+ st->i2c_tuner_gate_r = 5; -+ st->i2c_tuner_addr = 0xc0; -+ st->tuner_config = TUNER_S7395; -+ if (dvb_usb_lme2510_firmware != TUNER_S7395) { -+ dvb_usb_lme2510_firmware = TUNER_S7395; -+ ret = lme_firmware_switch(adap->dev->udev, 1); -+ } -+ break; - } -- goto end; -- } -+ case 0x22f0: -+ st->i2c_gate = 5; -+ adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach, -+ &m88rs2000_config, &adap->dev->i2c_adap); - -- st->i2c_gate = 5; -- adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config, -- &adap->dev->i2c_adap); -- if (adap->fe_adap[0].fe) { -- info("FE Found Stv0288"); -- st->i2c_tuner_gate_w = 4; -- st->i2c_tuner_gate_r = 5; -- st->i2c_tuner_addr = 0xc0; -- st->tuner_config = TUNER_S7395; -- if (dvb_usb_lme2510_firmware != TUNER_S7395) { -- dvb_usb_lme2510_firmware = TUNER_S7395; -- ret = lme_firmware_switch(adap->dev->udev, 1); -+ if (adap->fe_adap[0].fe) { -+ info("FE Found M88RS2000"); -+ st->i2c_tuner_gate_w = 5; -+ st->i2c_tuner_gate_r = 5; -+ st->i2c_tuner_addr = 0xc0; -+ st->tuner_config = TUNER_RS2000; -+ adap->fe_adap[0].fe->ops.read_signal_strength = -+ dm04_rs2000_read_signal_strength; -+ adap->fe_adap[0].fe->ops.read_snr = -+ dm04_rs2000_read_snr; - } -- } else { -- info("DM04 Not Supported"); -- return -ENODEV; -+ break; - } - -+ if (adap->fe_adap[0].fe == NULL) { -+ info("DM04/QQBOX Not Powered up or not Supported"); -+ return -ENODEV; -+ } - --end: if (ret) { -+ if (ret) { - if (adap->fe_adap[0].fe) { - dvb_frontend_detach(adap->fe_adap[0].fe); - adap->fe_adap[0].fe = NULL; -@@ -1028,7 +1131,7 @@ end: if (ret) { - static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) - { - struct lme2510_state *st = adap->dev->priv; -- char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"}; -+ char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"}; - int ret = 0; - - switch (st->tuner_config) { -@@ -1047,6 +1150,9 @@ static int dm04_lme2510_tuner(struct dvb - &adap->dev->i2c_adap, DVB_PLL_OPERA1)) - ret = st->tuner_config; - break; -+ case TUNER_RS2000: -+ ret = st->tuner_config; -+ break; - default: - break; - } -@@ -1054,7 +1160,7 @@ static int dm04_lme2510_tuner(struct dvb - if (ret) - info("TUN Found %s tuner", tun_msg[ret]); - else { -- info("TUN No tuner found --- reseting device"); -+ info("TUN No tuner found --- resetting device"); - lme_coldreset(adap->dev->udev); - return -ENODEV; - } -@@ -1075,10 +1181,9 @@ static int lme2510_powerup(struct dvb_us - static u8 lnb_on[] = LNB_ON; - static u8 lnb_off[] = LNB_OFF; - static u8 rbuf[1]; -- int ret, len = 3, rlen = 1; -+ int ret = 0, len = 3, rlen = 1; - -- if (mutex_lock_interruptible(&d->i2c_mutex) < 0) -- return -EAGAIN; -+ mutex_lock(&d->i2c_mutex); - - if (onoff) - ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen); -@@ -1136,6 +1241,7 @@ static int lme2510_probe(struct usb_inte - static struct usb_device_id lme2510_table[] = { - { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */ - { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */ -+ { USB_DEVICE(0x3344, 0x22f0) }, /* LME2510C RS2000 */ - {} /* Terminating entry */ - }; - -@@ -1153,7 +1259,7 @@ static struct dvb_usb_device_properties - DVB_USB_ADAP_NEED_PID_FILTERING| - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .streaming_ctrl = lme2510_streaming_ctrl, -- .pid_filter_count = 15, -+ .pid_filter_count = 32, - .pid_filter = lme2510_pid_filter, - .pid_filter_ctrl = lme2510_pid_filter_ctrl, - .frontend_attach = dm04_lme2510_frontend_attach, -@@ -1204,7 +1310,7 @@ static struct dvb_usb_device_properties - DVB_USB_ADAP_NEED_PID_FILTERING| - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .streaming_ctrl = lme2510_streaming_ctrl, -- .pid_filter_count = 15, -+ .pid_filter_count = 32, - .pid_filter = lme2510_pid_filter, - .pid_filter_ctrl = lme2510_pid_filter_ctrl, - .frontend_attach = dm04_lme2510_frontend_attach, -@@ -1234,11 +1340,14 @@ static struct dvb_usb_device_properties - .identify_state = lme2510_identify_state, - .i2c_algo = &lme2510_i2c_algo, - .generic_bulk_ctrl_endpoint = 0, -- .num_device_descs = 1, -+ .num_device_descs = 2, - .devices = { - { "DM04_LME2510C_DVB-S", - { &lme2510_table[1], NULL }, - }, -+ { "DM04_LME2510C_DVB-S RS2000", -+ { &lme2510_table[2], NULL }, -+ }, - } - }; - -@@ -1295,5 +1404,5 @@ module_usb_driver(lme2510_driver); - - MODULE_AUTHOR("Malcolm Priestley "); - MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); --MODULE_VERSION("1.91"); -+MODULE_VERSION("1.99"); - MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/video/ov6650.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ov6650.c -+++ linux-3.3.x86_64/drivers/media/video/ov6650.c -@@ -649,7 +649,7 @@ static int ov6650_s_fmt(struct v4l2_subd - clkrc = CLKRC_24MHz; - } else { - dev_err(&client->dev, -- "unspported input clock, check platform data\n"); -+ "unsupported input clock, check platform data\n"); - return -EINVAL; - } - mclk = sense->master_clock; -@@ -1046,18 +1046,7 @@ static struct i2c_driver ov6650_i2c_driv - .id_table = ov6650_id, - }; - --static int __init ov6650_module_init(void) --{ -- return i2c_add_driver(&ov6650_i2c_driver); --} -- --static void __exit ov6650_module_exit(void) --{ -- i2c_del_driver(&ov6650_i2c_driver); --} -- --module_init(ov6650_module_init); --module_exit(ov6650_module_exit); -+module_i2c_driver(ov6650_i2c_driver); - - MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650"); - MODULE_AUTHOR("Janusz Krzysztofik "); -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/tda1004x.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/tda1004x.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/tda1004x.c -@@ -1272,7 +1272,7 @@ struct dvb_frontend* tda10045_attach(con - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); - if (!state) { -- printk(KERN_ERR "Can't alocate memory for tda10045 state\n"); -+ printk(KERN_ERR "Can't allocate memory for tda10045 state\n"); - return NULL; - } - -@@ -1342,7 +1342,7 @@ struct dvb_frontend* tda10046_attach(con - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); - if (!state) { -- printk(KERN_ERR "Can't alocate memory for tda10046 state\n"); -+ printk(KERN_ERR "Can't allocate memory for tda10046 state\n"); - return NULL; - } - -Index: linux-3.3.x86_64/drivers/media/video/davinci/vpif.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/davinci/vpif.h -+++ linux-3.3.x86_64/drivers/media/video/davinci/vpif.h -@@ -18,8 +18,6 @@ - - #include - #include --#include --#include - #include - - /* Maximum channel allowed */ -Index: linux-3.3.x86_64/drivers/media/video/davinci/vpif_display.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/davinci/vpif_display.c -+++ linux-3.3.x86_64/drivers/media/video/davinci/vpif_display.c -@@ -39,8 +39,6 @@ - #include - #include - --#include -- - #include "vpif_display.h" - #include "vpif.h" - -Index: linux-3.3.x86_64/include/media/davinci/vpif_types.h -=================================================================== ---- linux-3.3.x86_64.orig/include/media/davinci/vpif_types.h -+++ linux-3.3.x86_64/include/media/davinci/vpif_types.h -@@ -17,6 +17,8 @@ - #ifndef _VPIF_TYPES_H - #define _VPIF_TYPES_H - -+#include -+ - #define VPIF_CAPTURE_MAX_CHANNELS 2 - - enum vpif_if_type { -Index: linux-3.3.x86_64/drivers/media/video/tm6000/tm6000-input.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tm6000/tm6000-input.c -+++ linux-3.3.x86_64/drivers/media/video/tm6000/tm6000-input.c -@@ -481,8 +481,6 @@ int tm6000_ir_fini(struct tm6000_core *d - - dprintk(2, "%s\n",__func__); - -- rc_unregister_device(ir->rc); -- - if (!ir->polling) - __tm6000_ir_int_stop(ir->rc); - -@@ -492,6 +490,7 @@ int tm6000_ir_fini(struct tm6000_core *d - tm6000_flash_led(dev, 0); - ir->pwled = 0; - -+ rc_unregister_device(ir->rc); - - kfree(ir); - dev->ir = NULL; -Index: linux-3.3.x86_64/drivers/media/dvb/mantis/mantis_hif.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/mantis/mantis_hif.c -+++ linux-3.3.x86_64/drivers/media/dvb/mantis/mantis_hif.c -@@ -76,7 +76,7 @@ static int mantis_hif_write_wait(struct - udelay(500); - timeout++; - if (timeout > 100) { -- dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num); -+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write operation timed out!", mantis->num); - rc = -ETIMEDOUT; - break; - } -Index: linux-3.3.x86_64/drivers/media/common/tuners/max2165.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/common/tuners/max2165.c -+++ linux-3.3.x86_64/drivers/media/common/tuners/max2165.c -@@ -168,7 +168,7 @@ int fixpt_div32(u32 dividend, u32 diviso - int i; - - if (0 == divisor) -- return -1; -+ return -EINVAL; - - q = dividend / divisor; - remainder = dividend - q * divisor; -@@ -194,10 +194,13 @@ static int max2165_set_rf(struct max2165 - u8 tf_ntch; - u32 t; - u32 quotient, fraction; -+ int ret; - - /* Set PLL divider according to RF frequency */ -- fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, -- "ient, &fraction); -+ ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, -+ "ient, &fraction); -+ if (ret != 0) -+ return ret; - - /* 20-bit fraction */ - fraction >>= 12; -Index: linux-3.3.x86_64/drivers/media/video/v4l2-compat-ioctl32.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/v4l2-compat-ioctl32.c -+++ linux-3.3.x86_64/drivers/media/video/v4l2-compat-ioctl32.c -@@ -14,12 +14,11 @@ - */ - - #include --#include - #include -+#include -+#include - #include - --#ifdef CONFIG_COMPAT -- - static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - { - long ret = -ENOIOCTLCMD; -@@ -937,6 +936,7 @@ static long do_video_ioctl(struct file * - - long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) - { -+ struct video_device *vdev = video_devdata(file); - long ret = -ENOIOCTLCMD; - - if (!file->f_op->unlocked_ioctl) -@@ -1005,6 +1005,8 @@ long v4l2_compat_ioctl32(struct file *fi - case VIDIOC_G_ENC_INDEX: - case VIDIOC_ENCODER_CMD: - case VIDIOC_TRY_ENCODER_CMD: -+ case VIDIOC_DECODER_CMD: -+ case VIDIOC_TRY_DECODER_CMD: - case VIDIOC_DBG_S_REGISTER: - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_G_CHIP_IDENT: -@@ -1025,14 +1027,16 @@ long v4l2_compat_ioctl32(struct file *fi - break; - - default: -- printk(KERN_WARNING "compat_ioctl32: " -- "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", -- _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd); -+ if (vdev->fops->compat_ioctl32) -+ ret = vdev->fops->compat_ioctl32(file, cmd, arg); -+ -+ if (ret == -ENOIOCTLCMD) -+ printk(KERN_WARNING "compat_ioctl32: " -+ "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", -+ _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), -+ cmd); - break; - } - return ret; - } - EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); --#endif -- --MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/include/media/v4l2-ioctl.h -=================================================================== ---- linux-3.3.x86_64.orig/include/media/v4l2-ioctl.h -+++ linux-3.3.x86_64/include/media/v4l2-ioctl.h -@@ -211,6 +211,10 @@ struct v4l2_ioctl_ops { - struct v4l2_encoder_cmd *a); - int (*vidioc_try_encoder_cmd) (struct file *file, void *fh, - struct v4l2_encoder_cmd *a); -+ int (*vidioc_decoder_cmd) (struct file *file, void *fh, -+ struct v4l2_decoder_cmd *a); -+ int (*vidioc_try_decoder_cmd) (struct file *file, void *fh, -+ struct v4l2_decoder_cmd *a); - - /* Stream type-dependent parameter ioctls */ - int (*vidioc_g_parm) (struct file *file, void *fh, -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-driver.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-driver.c -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-driver.c -@@ -55,7 +55,7 @@ - #include "ivtv-routing.h" - #include "ivtv-controls.h" - #include "ivtv-gpio.h" -- -+#include - #include - #include - #include -@@ -99,7 +99,7 @@ static int i2c_clock_period[IVTV_MAX_CAR - - static unsigned int cardtype_c = 1; - static unsigned int tuner_c = 1; --static bool radio_c = 1; -+static int radio_c = 1; - static unsigned int i2c_clock_period_c = 1; - static char pal[] = "---"; - static char secam[] = "--"; -@@ -139,7 +139,7 @@ static int tunertype = -1; - static int newi2c = -1; - - module_param_array(tuner, int, &tuner_c, 0644); --module_param_array(radio, bool, &radio_c, 0644); -+module_param_array(radio, int, &radio_c, 0644); - module_param_array(cardtype, int, &cardtype_c, 0644); - module_param_string(pal, pal, sizeof(pal), 0644); - module_param_string(secam, secam, sizeof(secam), 0644); -@@ -744,8 +744,6 @@ static int __devinit ivtv_init_struct1(s - - itv->cur_dma_stream = -1; - itv->cur_pio_stream = -1; -- itv->audio_stereo_mode = AUDIO_STEREO; -- itv->audio_bilingual_mode = AUDIO_MONO_LEFT; - - /* Ctrls */ - itv->speed = 1000; -@@ -815,7 +813,7 @@ static int ivtv_setup_pci(struct ivtv *i - IVTV_ERR("Can't enable device!\n"); - return -EIO; - } -- if (pci_set_dma_mask(pdev, 0xffffffff)) { -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - IVTV_ERR("No suitable DMA available.\n"); - return -EIO; - } -@@ -1200,6 +1198,32 @@ static int __devinit ivtv_probe(struct p - itv->tuner_std = itv->std; - - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { -+ struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler; -+ -+ itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops, -+ V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0); -+ itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops, -+ V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0); -+ /* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported, -+ mask that menu item. */ -+ itv->ctrl_audio_playback = -+ v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops, -+ V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO, -+ 1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO); -+ itv->ctrl_audio_multilingual_playback = -+ v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops, -+ V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO, -+ 1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO, -+ V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT); -+ if (hdl->error) { -+ retval = hdl->error; -+ goto free_i2c; -+ } -+ v4l2_ctrl_cluster(2, &itv->ctrl_pts); -+ v4l2_ctrl_cluster(2, &itv->ctrl_audio_playback); - ivtv_call_all(itv, video, s_std_output, itv->std); - /* Turn off the output signal. The mpeg decoder is not yet - active so without this you would get a green image until the -@@ -1236,6 +1260,7 @@ free_streams: - free_irq: - free_irq(itv->pdev->irq, (void *)itv); - free_i2c: -+ v4l2_ctrl_handler_free(&itv->cxhdl.hdl); - exit_ivtv_i2c(itv); - free_io: - ivtv_iounmap(itv); -@@ -1375,7 +1400,7 @@ static void ivtv_remove(struct pci_dev * - else - type = IVTV_DEC_STREAM_TYPE_MPG; - ivtv_stop_v4l2_decode_stream(&itv->streams[type], -- VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); -+ V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0); - } - ivtv_halt_firmware(itv); - } -@@ -1391,6 +1416,8 @@ static void ivtv_remove(struct pci_dev * - ivtv_streams_cleanup(itv, 1); - ivtv_udma_free(itv); - -+ v4l2_ctrl_handler_free(&itv->cxhdl.hdl); -+ - exit_ivtv_i2c(itv); - - free_irq(itv->pdev->irq, (void *)itv); -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-fileops.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-fileops.c -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-fileops.c -@@ -746,8 +746,9 @@ unsigned int ivtv_v4l2_dec_poll(struct f - return res; - } - --unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) -+unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait) - { -+ unsigned long req_events = poll_requested_events(wait); - struct ivtv_open_id *id = fh2id(filp->private_data); - struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; -@@ -755,7 +756,8 @@ unsigned int ivtv_v4l2_enc_poll(struct f - unsigned res = 0; - - /* Start a capture if there is none */ -- if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { -+ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags) && -+ (req_events & (POLLIN | POLLRDNORM))) { - int rc; - - rc = ivtv_start_capture(id); -@@ -900,7 +902,7 @@ int ivtv_v4l2_close(struct file *filp) - if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { - struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; - -- ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); -+ ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0); - - /* If all output streams are closed, and if the user doesn't have - IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ -Index: linux-3.3.x86_64/drivers/media/video/v4l2-ctrls.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/v4l2-ctrls.c -+++ linux-3.3.x86_64/drivers/media/video/v4l2-ctrls.c -@@ -175,6 +175,15 @@ const char * const *v4l2_ctrl_get_menu(u - "16-bit CRC", - NULL - }; -+ static const char * const mpeg_audio_dec_playback[] = { -+ "Auto", -+ "Stereo", -+ "Left", -+ "Right", -+ "Mono", -+ "Swapped Stereo", -+ NULL -+ }; - static const char * const mpeg_video_encoding[] = { - "MPEG-1", - "MPEG-2", -@@ -236,8 +245,8 @@ const char * const *v4l2_ctrl_get_menu(u - }; - static const char * const tune_preemphasis[] = { - "No Preemphasis", -- "50 useconds", -- "75 useconds", -+ "50 Microseconds", -+ "75 Microseconds", - NULL, - }; - static const char * const header_mode[] = { -@@ -334,7 +343,7 @@ const char * const *v4l2_ctrl_get_menu(u - }; - static const char * const mpeg4_profile[] = { - "Simple", -- "Adcanved Simple", -+ "Advanced Simple", - "Core", - "Simple Scalable", - "Advanced Coding Efficency", -@@ -353,6 +362,16 @@ const char * const *v4l2_ctrl_get_menu(u - NULL, - }; - -+ static const char * const jpeg_chroma_subsampling[] = { -+ "4:4:4", -+ "4:2:2", -+ "4:2:0", -+ "4:1:1", -+ "4:1:0", -+ "Gray", -+ NULL, -+ }; -+ - switch (id) { - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - return mpeg_audio_sampling_freq; -@@ -374,6 +393,9 @@ const char * const *v4l2_ctrl_get_menu(u - return mpeg_audio_emphasis; - case V4L2_CID_MPEG_AUDIO_CRC: - return mpeg_audio_crc; -+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: -+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: -+ return mpeg_audio_dec_playback; - case V4L2_CID_MPEG_VIDEO_ENCODING: - return mpeg_video_encoding; - case V4L2_CID_MPEG_VIDEO_ASPECT: -@@ -414,6 +436,9 @@ const char * const *v4l2_ctrl_get_menu(u - return mpeg_mpeg4_level; - case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: - return mpeg4_profile; -+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: -+ return jpeg_chroma_subsampling; -+ - default: - return NULL; - } -@@ -492,6 +517,8 @@ const char *v4l2_ctrl_get_name(u32 id) - case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute"; - case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; -+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: return "Audio Playback"; -+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback"; - case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding"; - case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect"; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames"; -@@ -546,6 +573,8 @@ const char *v4l2_ctrl_get_name(u32 id) - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice"; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method"; - case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; -+ case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; -+ case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; - - /* CAMERA controls */ - /* Keep the order of the 'case's the same as in videodev2.h! */ -@@ -607,6 +636,14 @@ const char *v4l2_ctrl_get_name(u32 id) - case V4L2_CID_FLASH_CHARGE: return "Charge"; - case V4L2_CID_FLASH_READY: return "Ready to Strobe"; - -+ /* JPEG encoder controls */ -+ /* Keep the order of the 'case's the same as in videodev2.h! */ -+ case V4L2_CID_JPEG_CLASS: return "JPEG Compression Controls"; -+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: return "Chroma Subsampling"; -+ case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval"; -+ case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality"; -+ case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers"; -+ - default: - return NULL; - } -@@ -674,6 +711,8 @@ void v4l2_ctrl_fill(u32 id, const char * - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - case V4L2_CID_MPEG_AUDIO_CRC: -+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: -+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: - case V4L2_CID_MPEG_VIDEO_ENCODING: - case V4L2_CID_MPEG_VIDEO_ASPECT: - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: -@@ -693,6 +732,7 @@ void v4l2_ctrl_fill(u32 id, const char * - case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: - case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: - case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: -+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: - *type = V4L2_CTRL_TYPE_MENU; - break; - case V4L2_CID_RDS_TX_PS_NAME: -@@ -704,6 +744,7 @@ void v4l2_ctrl_fill(u32 id, const char * - case V4L2_CID_MPEG_CLASS: - case V4L2_CID_FM_TX_CLASS: - case V4L2_CID_FLASH_CLASS: -+ case V4L2_CID_JPEG_CLASS: - *type = V4L2_CTRL_TYPE_CTRL_CLASS; - /* You can neither read not write these */ - *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; -@@ -717,6 +758,7 @@ void v4l2_ctrl_fill(u32 id, const char * - *max = 0xFFFFFF; - break; - case V4L2_CID_FLASH_FAULT: -+ case V4L2_CID_JPEG_ACTIVE_MARKER: - *type = V4L2_CTRL_TYPE_BITMASK; - break; - case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: -@@ -724,6 +766,11 @@ void v4l2_ctrl_fill(u32 id, const char * - *type = V4L2_CTRL_TYPE_INTEGER; - *flags |= V4L2_CTRL_FLAG_READ_ONLY; - break; -+ case V4L2_CID_MPEG_VIDEO_DEC_FRAME: -+ case V4L2_CID_MPEG_VIDEO_DEC_PTS: -+ *type = V4L2_CTRL_TYPE_INTEGER64; -+ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE; -+ break; - default: - *type = V4L2_CTRL_TYPE_INTEGER; - break; -@@ -1470,7 +1517,7 @@ EXPORT_SYMBOL(v4l2_ctrl_add_ctrl); - int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, - struct v4l2_ctrl_handler *add) - { -- struct v4l2_ctrl *ctrl; -+ struct v4l2_ctrl_ref *ref; - int ret = 0; - - /* Do nothing if either handler is NULL or if they are the same */ -@@ -1479,7 +1526,9 @@ int v4l2_ctrl_add_handler(struct v4l2_ct - if (hdl->error) - return hdl->error; - mutex_lock(&add->lock); -- list_for_each_entry(ctrl, &add->ctrls, node) { -+ list_for_each_entry(ref, &add->ctrl_refs, node) { -+ struct v4l2_ctrl *ctrl = ref->ctrl; -+ - /* Skip handler-private controls. */ - if (ctrl->is_private) - continue; -@@ -2359,3 +2408,35 @@ void v4l2_ctrl_del_event(struct v4l2_ctr - v4l2_ctrl_unlock(ctrl); - } - EXPORT_SYMBOL(v4l2_ctrl_del_event); -+ -+int v4l2_ctrl_log_status(struct file *file, void *fh) -+{ -+ struct video_device *vfd = video_devdata(file); -+ struct v4l2_fh *vfh = file->private_data; -+ -+ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) -+ v4l2_ctrl_handler_log_status(vfh->ctrl_handler, -+ vfd->v4l2_dev->name); -+ return 0; -+} -+EXPORT_SYMBOL(v4l2_ctrl_log_status); -+ -+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, -+ struct v4l2_event_subscription *sub) -+{ -+ if (sub->type == V4L2_EVENT_CTRL) -+ return v4l2_event_subscribe(fh, sub, 0); -+ return -EINVAL; -+} -+EXPORT_SYMBOL(v4l2_ctrl_subscribe_event); -+ -+unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) -+{ -+ struct v4l2_fh *fh = file->private_data; -+ -+ if (v4l2_event_pending(fh)) -+ return POLLPRI; -+ poll_wait(file, &fh->wait, wait); -+ return 0; -+} -+EXPORT_SYMBOL(v4l2_ctrl_poll); -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-controls.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-controls.c -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-controls.c -@@ -21,6 +21,7 @@ - #include "ivtv-driver.h" - #include "ivtv-ioctl.h" - #include "ivtv-controls.h" -+#include "ivtv-mailbox.h" - - static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) - { -@@ -99,3 +100,64 @@ struct cx2341x_handler_ops ivtv_cxhdl_op - .s_video_encoding = ivtv_s_video_encoding, - .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt, - }; -+ -+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame) -+{ -+ u32 data[CX2341X_MBOX_MAX_DATA]; -+ -+ if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { -+ *pts = (s64)((u64)itv->last_dec_timing[2] << 32) | -+ (u64)itv->last_dec_timing[1]; -+ *frame = itv->last_dec_timing[0]; -+ return 0; -+ } -+ *pts = 0; -+ *frame = 0; -+ if (atomic_read(&itv->decoding)) { -+ if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { -+ IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); -+ return -EIO; -+ } -+ memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); -+ set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); -+ *pts = (s64)((u64) data[2] << 32) | (u64) data[1]; -+ *frame = data[0]; -+ /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ -+ } -+ return 0; -+} -+ -+static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl); -+ -+ switch (ctrl->id) { -+ /* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME -+ control cluster */ -+ case V4L2_CID_MPEG_VIDEO_DEC_PTS: -+ return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64, -+ &itv->ctrl_frame->val64); -+ } -+ return 0; -+} -+ -+static int ivtv_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl); -+ -+ switch (ctrl->id) { -+ /* V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK and MULTILINGUAL_PLAYBACK -+ control cluster */ -+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: -+ itv->audio_stereo_mode = itv->ctrl_audio_playback->val - 1; -+ itv->audio_bilingual_mode = itv->ctrl_audio_multilingual_playback->val - 1; -+ ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); -+ break; -+ } -+ return 0; -+} -+ -+const struct v4l2_ctrl_ops ivtv_hdl_out_ops = { -+ .s_ctrl = ivtv_s_ctrl, -+ .g_volatile_ctrl = ivtv_g_volatile_ctrl, -+}; -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-controls.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-controls.h -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-controls.h -@@ -22,5 +22,7 @@ - #define IVTV_CONTROLS_H - - extern struct cx2341x_handler_ops ivtv_cxhdl_ops; -+extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops; -+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame); - - #endif -Index: linux-3.3.x86_64/drivers/media/dvb/ddbridge/ddbridge.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/ddbridge/ddbridge.h -+++ linux-3.3.x86_64/drivers/media/dvb/ddbridge/ddbridge.h -@@ -32,8 +32,6 @@ - #include - #include - #include --#include --#include - #include - - #include "dmxdev.h" -Index: linux-3.3.x86_64/drivers/media/video/cx18/cx18-driver.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx18/cx18-driver.h -+++ linux-3.3.x86_64/drivers/media/video/cx18/cx18-driver.h -@@ -44,8 +44,6 @@ - #include - #include - --#include --#include - #include - #include - #include -Index: linux-3.3.x86_64/include/linux/ivtv.h -=================================================================== ---- linux-3.3.x86_64.orig/include/linux/ivtv.h -+++ linux-3.3.x86_64/include/linux/ivtv.h -@@ -58,7 +58,11 @@ struct ivtv_dma_frame { - __u32 src_height; - }; - --#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) -+#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) -+ -+/* Select the passthrough mode (if the argument is non-zero). In the passthrough -+ mode the output of the encoder is passed immediately into the decoder. */ -+#define IVTV_IOC_PASSTHROUGH_MODE _IOW ('V', BASE_VIDIOC_PRIVATE+1, int) - - /* Deprecated defines: applications should use the defines from videodev2.h */ - #define IVTV_SLICED_TYPE_TELETEXT_B V4L2_MPEG_VBI_IVTV_TELETEXT_B -Index: linux-3.3.x86_64/drivers/media/rc/keymaps/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/keymaps/Makefile -+++ linux-3.3.x86_64/drivers/media/rc/keymaps/Makefile -@@ -41,8 +41,11 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t - rc-imon-mce.o \ - rc-imon-pad.o \ - rc-iodata-bctv7e.o \ -+ rc-it913x-v1.o \ -+ rc-it913x-v2.o \ - rc-kaiomy.o \ - rc-kworld-315u.o \ -+ rc-kworld-pc150u.o \ - rc-kworld-plus-tv-analog.o \ - rc-leadtek-y04g0051.o \ - rc-lirc.o \ -Index: linux-3.3.x86_64/drivers/media/rc/keymaps/rc-it913x-v1.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/rc/keymaps/rc-it913x-v1.c -@@ -0,0 +1,95 @@ -+/* ITE Generic remotes Version 1 -+ * -+ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+ -+static struct rc_map_table it913x_v1_rc[] = { -+ /* Type 1 */ -+ { 0x61d601, KEY_VIDEO }, /* Source */ -+ { 0x61d602, KEY_3 }, -+ { 0x61d603, KEY_POWER }, /* ShutDown */ -+ { 0x61d604, KEY_1 }, -+ { 0x61d605, KEY_5 }, -+ { 0x61d606, KEY_6 }, -+ { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ -+ { 0x61d608, KEY_2 }, -+ { 0x61d609, KEY_CHANNELUP }, /* CH+ */ -+ { 0x61d60a, KEY_9 }, -+ { 0x61d60b, KEY_ZOOM }, /* Zoom */ -+ { 0x61d60c, KEY_7 }, -+ { 0x61d60d, KEY_8 }, -+ { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ -+ { 0x61d60f, KEY_4 }, -+ { 0x61d610, KEY_ESC }, /* [back up arrow] */ -+ { 0x61d611, KEY_0 }, -+ { 0x61d612, KEY_OK }, /* [enter arrow] */ -+ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ -+ { 0x61d614, KEY_RECORD }, /* Rec */ -+ { 0x61d615, KEY_STOP }, /* Stop */ -+ { 0x61d616, KEY_PLAY }, /* Play */ -+ { 0x61d617, KEY_MUTE }, /* Mute */ -+ { 0x61d618, KEY_UP }, -+ { 0x61d619, KEY_DOWN }, -+ { 0x61d61a, KEY_LEFT }, -+ { 0x61d61b, KEY_RIGHT }, -+ { 0x61d61c, KEY_RED }, -+ { 0x61d61d, KEY_GREEN }, -+ { 0x61d61e, KEY_YELLOW }, -+ { 0x61d61f, KEY_BLUE }, -+ { 0x61d643, KEY_POWER2 }, /* [red power button] */ -+ /* Type 2 - 20 buttons */ -+ { 0x807f0d, KEY_0 }, -+ { 0x807f04, KEY_1 }, -+ { 0x807f05, KEY_2 }, -+ { 0x807f06, KEY_3 }, -+ { 0x807f07, KEY_4 }, -+ { 0x807f08, KEY_5 }, -+ { 0x807f09, KEY_6 }, -+ { 0x807f0a, KEY_7 }, -+ { 0x807f1b, KEY_8 }, -+ { 0x807f1f, KEY_9 }, -+ { 0x807f12, KEY_POWER }, -+ { 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */ -+ { 0x807f19, KEY_PAUSE }, /* Timeshift */ -+ { 0x807f1e, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ -+ { 0x807f03, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ -+ { 0x807f1a, KEY_CHANNELUP }, -+ { 0x807f02, KEY_CHANNELDOWN }, -+ { 0x807f0c, KEY_ZOOM }, -+ { 0x807f00, KEY_RECORD }, -+ { 0x807f0e, KEY_STOP }, -+}; -+ -+static struct rc_map_list it913x_v1_map = { -+ .map = { -+ .scan = it913x_v1_rc, -+ .size = ARRAY_SIZE(it913x_v1_rc), -+ .rc_type = RC_TYPE_NEC, -+ .name = RC_MAP_IT913X_V1, -+ } -+}; -+ -+static int __init init_rc_it913x_v1_map(void) -+{ -+ return rc_map_register(&it913x_v1_map); -+} -+ -+static void __exit exit_rc_it913x_v1_map(void) -+{ -+ rc_map_unregister(&it913x_v1_map); -+} -+ -+module_init(init_rc_it913x_v1_map) -+module_exit(exit_rc_it913x_v1_map) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); -Index: linux-3.3.x86_64/drivers/media/rc/keymaps/rc-it913x-v2.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/rc/keymaps/rc-it913x-v2.c -@@ -0,0 +1,94 @@ -+/* ITE Generic remotes Version 2 -+ * -+ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+ -+static struct rc_map_table it913x_v2_rc[] = { -+ /* Type 1 */ -+ /* 9005 remote */ -+ { 0x807f12, KEY_POWER2 }, /* Power (RED POWER BUTTON)*/ -+ { 0x807f1a, KEY_VIDEO }, /* Source */ -+ { 0x807f1e, KEY_MUTE }, /* Mute */ -+ { 0x807f01, KEY_RECORD }, /* Record */ -+ { 0x807f02, KEY_CHANNELUP }, /* Channel+ */ -+ { 0x807f03, KEY_TIME }, /* TimeShift */ -+ { 0x807f04, KEY_VOLUMEUP }, /* Volume- */ -+ { 0x807f05, KEY_SCREEN }, /* FullScreen */ -+ { 0x807f06, KEY_VOLUMEDOWN }, /* Volume- */ -+ { 0x807f07, KEY_0 }, /* 0 */ -+ { 0x807f08, KEY_CHANNELDOWN }, /* Channel- */ -+ { 0x807f09, KEY_PREVIOUS }, /* Recall */ -+ { 0x807f0a, KEY_1 }, /* 1 */ -+ { 0x807f1b, KEY_2 }, /* 2 */ -+ { 0x807f1f, KEY_3 }, /* 3 */ -+ { 0x807f0c, KEY_4 }, /* 4 */ -+ { 0x807f0d, KEY_5 }, /* 5 */ -+ { 0x807f0e, KEY_6 }, /* 6 */ -+ { 0x807f00, KEY_7 }, /* 7 */ -+ { 0x807f0f, KEY_8 }, /* 8 */ -+ { 0x807f19, KEY_9 }, /* 9 */ -+ -+ /* Type 2 */ -+ /* keys stereo, snapshot unassigned */ -+ { 0x866b00, KEY_0 }, -+ { 0x866b1b, KEY_1 }, -+ { 0x866b02, KEY_2 }, -+ { 0x866b03, KEY_3 }, -+ { 0x866b04, KEY_4 }, -+ { 0x866b05, KEY_5 }, -+ { 0x866b06, KEY_6 }, -+ { 0x866b07, KEY_7 }, -+ { 0x866b08, KEY_8 }, -+ { 0x866b09, KEY_9 }, -+ { 0x866b12, KEY_POWER }, -+ { 0x866b13, KEY_MUTE }, -+ { 0x866b0a, KEY_PREVIOUS }, /* Recall */ -+ { 0x866b1e, KEY_PAUSE }, -+ { 0x866b0c, KEY_VOLUMEUP }, -+ { 0x866b18, KEY_VOLUMEDOWN }, -+ { 0x866b0b, KEY_CHANNELUP }, -+ { 0x866b18, KEY_CHANNELDOWN }, -+ { 0x866b10, KEY_ZOOM }, -+ { 0x866b1d, KEY_RECORD }, -+ { 0x866b0e, KEY_STOP }, -+ { 0x866b11, KEY_EPG}, -+ { 0x866b1a, KEY_FASTFORWARD }, -+ { 0x866b0f, KEY_REWIND }, -+ { 0x866b1c, KEY_TV }, -+ { 0x866b1b, KEY_TEXT }, -+ -+}; -+ -+static struct rc_map_list it913x_v2_map = { -+ .map = { -+ .scan = it913x_v2_rc, -+ .size = ARRAY_SIZE(it913x_v2_rc), -+ .rc_type = RC_TYPE_NEC, -+ .name = RC_MAP_IT913X_V2, -+ } -+}; -+ -+static int __init init_rc_it913x_v2_map(void) -+{ -+ return rc_map_register(&it913x_v2_map); -+} -+ -+static void __exit exit_rc_it913x_v2_map(void) -+{ -+ rc_map_unregister(&it913x_v2_map); -+} -+ -+module_init(init_rc_it913x_v2_map) -+module_exit(exit_rc_it913x_v2_map) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); -Index: linux-3.3.x86_64/include/media/rc-map.h -=================================================================== ---- linux-3.3.x86_64.orig/include/media/rc-map.h -+++ linux-3.3.x86_64/include/media/rc-map.h -@@ -102,8 +102,11 @@ void rc_map_init(void); - #define RC_MAP_IMON_MCE "rc-imon-mce" - #define RC_MAP_IMON_PAD "rc-imon-pad" - #define RC_MAP_IODATA_BCTV7E "rc-iodata-bctv7e" -+#define RC_MAP_IT913X_V1 "rc-it913x-v1" -+#define RC_MAP_IT913X_V2 "rc-it913x-v2" - #define RC_MAP_KAIOMY "rc-kaiomy" - #define RC_MAP_KWORLD_315U "rc-kworld-315u" -+#define RC_MAP_KWORLD_PC150U "rc-kworld-pc150u" - #define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" - #define RC_MAP_LEADTEK_Y04G0051 "rc-leadtek-y04g0051" - #define RC_MAP_LIRC "rc-lirc" -Index: linux-3.3.x86_64/drivers/media/video/bt8xx/bttv-driver.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/bt8xx/bttv-driver.c -+++ linux-3.3.x86_64/drivers/media/video/bt8xx/bttv-driver.c -@@ -2035,11 +2035,7 @@ static int bttv_log_status(struct file * - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - -- pr_info("%d: ======== START STATUS CARD #%d ========\n", -- btv->c.nr, btv->c.nr); - bttv_call_all(btv, core, log_status); -- pr_info("%d: ======== END STATUS CARD #%d ========\n", -- btv->c.nr, btv->c.nr); - return 0; - } - -Index: linux-3.3.x86_64/drivers/media/video/cx18/cx18-ioctl.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx18/cx18-ioctl.c -+++ linux-3.3.x86_64/drivers/media/video/cx18/cx18-ioctl.c -@@ -1085,8 +1085,6 @@ static int cx18_log_status(struct file * - struct v4l2_audio audin; - int i; - -- CX18_INFO("================= START STATUS CARD #%d " -- "=================\n", cx->instance); - CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); - if (cx->hw_flags & CX18_HW_TVEEPROM) { - struct tveeprom tv; -@@ -1120,8 +1118,6 @@ static int cx18_log_status(struct file * - CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", - (long long)cx->mpg_data_received, - (long long)cx->vbi_data_inserted); -- CX18_INFO("================== END STATUS CARD #%d " -- "==================\n", cx->instance); - return 0; - } - -Index: linux-3.3.x86_64/drivers/media/video/pwc/pwc-v4l.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/pwc/pwc-v4l.c -+++ linux-3.3.x86_64/drivers/media/video/pwc/pwc-v4l.c -@@ -1146,14 +1146,6 @@ leave: - return ret; - } - --static int pwc_log_status(struct file *file, void *priv) --{ -- struct pwc_device *pdev = video_drvdata(file); -- -- v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME); -- return 0; --} -- - const struct v4l2_ioctl_ops pwc_ioctl_ops = { - .vidioc_querycap = pwc_querycap, - .vidioc_enum_input = pwc_enum_input, -@@ -1169,9 +1161,11 @@ const struct v4l2_ioctl_ops pwc_ioctl_op - .vidioc_dqbuf = pwc_dqbuf, - .vidioc_streamon = pwc_streamon, - .vidioc_streamoff = pwc_streamoff, -- .vidioc_log_status = pwc_log_status, -+ .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_enum_framesizes = pwc_enum_framesizes, - .vidioc_enum_frameintervals = pwc_enum_frameintervals, - .vidioc_g_parm = pwc_g_parm, - .vidioc_s_parm = pwc_s_parm, -+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - }; -Index: linux-3.3.x86_64/drivers/media/video/saa7164/saa7164-encoder.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7164/saa7164-encoder.c -+++ linux-3.3.x86_64/drivers/media/video/saa7164/saa7164-encoder.c -@@ -791,11 +791,6 @@ static int vidioc_s_fmt_vid_cap(struct f - return 0; - } - --static int vidioc_log_status(struct file *file, void *priv) --{ -- return 0; --} -- - static int fill_queryctrl(struct saa7164_encoder_params *params, - struct v4l2_queryctrl *c) - { -@@ -1347,7 +1342,6 @@ static const struct v4l2_ioctl_ops mpeg_ - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, -- .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_chip_ident = saa7164_g_chip_ident, - #ifdef CONFIG_VIDEO_ADV_DEBUG -Index: linux-3.3.x86_64/drivers/media/video/saa7164/saa7164-vbi.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7164/saa7164-vbi.c -+++ linux-3.3.x86_64/drivers/media/video/saa7164/saa7164-vbi.c -@@ -730,11 +730,6 @@ static int vidioc_s_fmt_vid_cap(struct f - return 0; - } - --static int vidioc_log_status(struct file *file, void *priv) --{ -- return 0; --} -- - static int fill_queryctrl(struct saa7164_vbi_params *params, - struct v4l2_queryctrl *c) - { -@@ -1256,7 +1251,6 @@ static const struct v4l2_ioctl_ops vbi_i - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, -- .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, - #if 0 - .vidioc_g_chip_ident = saa7164_g_chip_ident, -Index: linux-3.3.x86_64/include/media/v4l2-ctrls.h -=================================================================== ---- linux-3.3.x86_64.orig/include/media/v4l2-ctrls.h -+++ linux-3.3.x86_64/include/media/v4l2-ctrls.h -@@ -33,6 +33,7 @@ struct video_device; - struct v4l2_subdev; - struct v4l2_subscribed_event; - struct v4l2_fh; -+struct poll_table_struct; - - /** struct v4l2_ctrl_ops - The control operations that the driver has to provide. - * @g_volatile_ctrl: Get a new value for this control. Generally only relevant -@@ -492,6 +493,18 @@ void v4l2_ctrl_add_event(struct v4l2_ctr - void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl, - struct v4l2_subscribed_event *sev); - -+/* Can be used as a vidioc_log_status function that just dumps all controls -+ associated with the filehandle. */ -+int v4l2_ctrl_log_status(struct file *file, void *fh); -+ -+/* Can be used as a vidioc_subscribe_event function that just subscribes -+ control events. */ -+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, -+ struct v4l2_event_subscription *sub); -+ -+/* Can be used as a poll function that just polls for control events. */ -+unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait); -+ - /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */ - int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc); - int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm); -Index: linux-3.3.x86_64/drivers/media/video/v4l2-subdev.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/v4l2-subdev.c -+++ linux-3.3.x86_64/drivers/media/video/v4l2-subdev.c -@@ -194,8 +194,16 @@ static long subdev_do_ioctl(struct file - } - #endif - -- case VIDIOC_LOG_STATUS: -- return v4l2_subdev_call(sd, core, log_status); -+ case VIDIOC_LOG_STATUS: { -+ int ret; -+ -+ pr_info("%s: ================= START STATUS =================\n", -+ sd->name); -+ ret = v4l2_subdev_call(sd, core, log_status); -+ pr_info("%s: ================== END STATUS ==================\n", -+ sd->name); -+ return ret; -+ } - - #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - case VIDIOC_SUBDEV_G_FMT: { -Index: linux-3.3.x86_64/drivers/media/radio/Kconfig -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/Kconfig -+++ linux-3.3.x86_64/drivers/media/radio/Kconfig -@@ -43,7 +43,7 @@ config USB_DSBR - - config RADIO_MAXIRADIO - tristate "Guillemot MAXI Radio FM 2000 radio" -- depends on VIDEO_V4L2 && PCI -+ depends on VIDEO_V4L2 && PCI && SND - ---help--- - Choose Y here if you have this radio card. This card may also be - found as Gemtek PCI FM. -@@ -80,6 +80,16 @@ config RADIO_SI4713 - To compile this driver as a module, choose M here: the - module will be called radio-si4713. - -+config USB_KEENE -+ tristate "Keene FM Transmitter USB support" -+ depends on USB && VIDEO_V4L2 -+ ---help--- -+ Say Y here if you want to connect this type of FM transmitter -+ to your computer's USB port. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called radio-keene. -+ - config RADIO_TEA5764 - tristate "TEA5764 I2C FM radio support" - depends on I2C && VIDEO_V4L2 -@@ -167,6 +177,10 @@ menuconfig V4L_RADIO_ISA_DRIVERS - - if V4L_RADIO_ISA_DRIVERS - -+config RADIO_ISA -+ depends on ISA -+ tristate -+ - config RADIO_CADET - tristate "ADS Cadet AM/FM Tuner" - depends on ISA && VIDEO_V4L2 -@@ -174,20 +188,13 @@ config RADIO_CADET - Choose Y here if you have one of these AM/FM radio cards, and then - fill in the port address below. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -- -- Further documentation on this driver can be found on the WWW at -- . -- - To compile this driver as a module, choose M here: the - module will be called radio-cadet. - - config RADIO_RTRACK - tristate "AIMSlab RadioTrack (aka RadioReveal) support" - depends on ISA && VIDEO_V4L2 -+ select RADIO_ISA - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. -@@ -201,11 +208,7 @@ config RADIO_RTRACK - You must also pass the module a suitable io parameter, 0x248 has - been reported to be used by these cards. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . More information is -- contained in the file -+ More information is contained in the file - . - - To compile this driver as a module, choose M here: the -@@ -214,7 +217,7 @@ config RADIO_RTRACK - config RADIO_RTRACK_PORT - hex "RadioTrack i/o port (0x20f or 0x30f)" - depends on RADIO_RTRACK=y -- default "20f" -+ default "30f" - help - Enter either 0x30f or 0x20f here. The card default is 0x30f, if you - haven't changed the jumper setting on the card. -@@ -222,14 +225,14 @@ config RADIO_RTRACK_PORT - config RADIO_RTRACK2 - tristate "AIMSlab RadioTrack II support" - depends on ISA && VIDEO_V4L2 -+ select RADIO_ISA - ---help--- - Choose Y here if you have this FM radio card, and then fill in the - port address below. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -+ Note: this driver hasn't been tested since a long time due to lack -+ of hardware. If you have this hardware, then please contact the -+ linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-rtrack2. -@@ -245,15 +248,11 @@ config RADIO_RTRACK2_PORT - config RADIO_AZTECH - tristate "Aztech/Packard Bell Radio" - depends on ISA && VIDEO_V4L2 -+ select RADIO_ISA - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -- - To compile this driver as a module, choose M here: the - module will be called radio-aztech. - -@@ -269,6 +268,7 @@ config RADIO_AZTECH_PORT - config RADIO_GEMTEK - tristate "GemTek Radio card (or compatible) support" - depends on ISA && VIDEO_V4L2 -+ select RADIO_ISA - ---help--- - Choose Y here if you have this FM radio card, and then fill in the - I/O port address and settings below. The following cards either have -@@ -278,23 +278,21 @@ config RADIO_GEMTEK - - Typhoon Radio card (some models) - - Hama Radio card - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -- - To compile this driver as a module, choose M here: the - module will be called radio-gemtek. - - config RADIO_GEMTEK_PORT -- hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)" -+ hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c)" - depends on RADIO_GEMTEK=y - default "34c" - help -- Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is -- 0x34c, if you haven't changed the jumper setting on the card. On -- Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O -+ Enter either 0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c here. The -+ card default is 0x34c, if you haven't changed the jumper setting -+ on the card. -+ -+ On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O - port is 0x20c, 0x248 or 0x28c. -+ - If automatic I/O port probing is enabled this port will be used only - in case of automatic probing failure, ie. as a fallback. - -@@ -318,11 +316,6 @@ config RADIO_MIROPCM20 - sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this - is required for the radio-miropcm20. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -- - To compile this driver as a module, choose M here: the - module will be called radio-miropcm20. - -@@ -332,11 +325,6 @@ config RADIO_SF16FMI - ---help--- - Choose Y here if you have one of these FM radio cards. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -- - To compile this driver as a module, choose M here: the - module will be called radio-sf16fmi. - -@@ -346,50 +334,35 @@ config RADIO_SF16FMR2 - ---help--- - Choose Y here if you have one of these FM radio cards. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found on the WWW at -- . -- - To compile this driver as a module, choose M here: the - module will be called radio-sf16fmr2. - - config RADIO_TERRATEC - tristate "TerraTec ActiveRadio ISA Standalone" - depends on ISA && VIDEO_V4L2 -+ select RADIO_ISA - ---help--- -- Choose Y here if you have this FM radio card, and then fill in the -- port address below. (TODO) -- -- Note: This driver is in its early stages. Right now volume and -- frequency control and muting works at least for me, but -- unfortunately I have not found anybody who wants to use this card -- with Linux. So if it is this what YOU are trying to do right now, -- PLEASE DROP ME A NOTE!! Rolf Offermanns . -+ Choose Y here if you have this FM radio card. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -+ Note: this driver hasn't been tested since a long time due to lack -+ of hardware. If you have this hardware, then please contact the -+ linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-terratec. - --config RADIO_TERRATEC_PORT -- hex "Terratec i/o port (normally 0x590)" -- depends on RADIO_TERRATEC=y -- default "590" -- help -- Fill in the I/O port of your TerraTec FM radio card. If unsure, go -- with the default. -- - config RADIO_TRUST - tristate "Trust FM radio card" - depends on ISA && VIDEO_V4L2 -+ select RADIO_ISA - help - This is a driver for the Trust FM radio cards. Say Y if you have - such a card and want to use it under Linux. - -+ Note: this driver hasn't been tested since a long time due to lack -+ of hardware. If you have this hardware, then please contact the -+ linux-media mailinglist. -+ - To compile this driver as a module, choose M here: the - module will be called radio-trust. - -@@ -404,14 +377,14 @@ config RADIO_TRUST_PORT - config RADIO_TYPHOON - tristate "Typhoon Radio (a.k.a. EcoRadio)" - depends on ISA && VIDEO_V4L2 -+ select RADIO_ISA - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address and the frequency used for muting below. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -+ Note: this driver hasn't been tested since a long time due to lack -+ of hardware. If you have this hardware, then please contact the -+ linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-typhoon. -@@ -438,14 +411,14 @@ config RADIO_TYPHOON_MUTEFREQ - config RADIO_ZOLTRIX - tristate "Zoltrix Radio" - depends on ISA && VIDEO_V4L2 -+ select RADIO_ISA - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - -- In order to control your radio card, you will need to use programs -- that are compatible with the Video For Linux API. Information on -- this API and pointers to "v4l" programs may be found at -- . -+ Note: this driver hasn't been tested since a long time due to lack -+ of hardware. If you have this hardware, then please contact the -+ linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-zoltrix. -Index: linux-3.3.x86_64/drivers/media/radio/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/Makefile -+++ linux-3.3.x86_64/drivers/media/radio/Makefile -@@ -2,6 +2,7 @@ - # Makefile for the kernel character device drivers. - # - -+obj-$(CONFIG_RADIO_ISA) += radio-isa.o - obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o - obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o - obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o -@@ -20,6 +21,7 @@ obj-$(CONFIG_RADIO_MIROPCM20) += radio-m - obj-$(CONFIG_USB_DSBR) += dsbr100.o - obj-$(CONFIG_RADIO_SI470X) += si470x/ - obj-$(CONFIG_USB_MR800) += radio-mr800.o -+obj-$(CONFIG_USB_KEENE) += radio-keene.o - obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o - obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o - obj-$(CONFIG_RADIO_TEF6862) += tef6862.o -Index: linux-3.3.x86_64/drivers/media/radio/radio-keene.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/radio/radio-keene.c -@@ -0,0 +1,427 @@ -+/* -+ * Copyright (c) 2012 Hans Verkuil -+ * -+ * 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 -+ */ -+ -+/* kernel includes */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* driver and module definitions */ -+MODULE_AUTHOR("Hans Verkuil "); -+MODULE_DESCRIPTION("Keene FM Transmitter driver"); -+MODULE_LICENSE("GPL"); -+ -+/* Actually, it advertises itself as a Logitech */ -+#define USB_KEENE_VENDOR 0x046d -+#define USB_KEENE_PRODUCT 0x0a0e -+ -+/* Probably USB_TIMEOUT should be modified in module parameter */ -+#define BUFFER_LENGTH 8 -+#define USB_TIMEOUT 500 -+ -+/* Frequency limits in MHz */ -+#define FREQ_MIN 76U -+#define FREQ_MAX 108U -+#define FREQ_MUL 16000U -+ -+/* USB Device ID List */ -+static struct usb_device_id usb_keene_device_table[] = { -+ {USB_DEVICE_AND_INTERFACE_INFO(USB_KEENE_VENDOR, USB_KEENE_PRODUCT, -+ USB_CLASS_HID, 0, 0) }, -+ { } /* Terminating entry */ -+}; -+ -+MODULE_DEVICE_TABLE(usb, usb_keene_device_table); -+ -+struct keene_device { -+ struct usb_device *usbdev; -+ struct usb_interface *intf; -+ struct video_device vdev; -+ struct v4l2_device v4l2_dev; -+ struct v4l2_ctrl_handler hdl; -+ struct mutex lock; -+ -+ u8 *buffer; -+ unsigned curfreq; -+ u8 tx; -+ u8 pa; -+ bool stereo; -+ bool muted; -+ bool preemph_75_us; -+}; -+ -+static inline struct keene_device *to_keene_dev(struct v4l2_device *v4l2_dev) -+{ -+ return container_of(v4l2_dev, struct keene_device, v4l2_dev); -+} -+ -+/* Set frequency (if non-0), PA, mute and turn on/off the FM transmitter. */ -+static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play) -+{ -+ unsigned short freq_send = freq ? (freq - 76 * 16000) / 800 : 0; -+ int ret; -+ -+ radio->buffer[0] = 0x00; -+ radio->buffer[1] = 0x50; -+ radio->buffer[2] = (freq_send >> 8) & 0xff; -+ radio->buffer[3] = freq_send & 0xff; -+ radio->buffer[4] = radio->pa; -+ /* If bit 4 is set, then tune to the frequency. -+ If bit 3 is set, then unmute; if bit 2 is set, then mute. -+ If bit 1 is set, then enter idle mode; if bit 0 is set, -+ then enter transit mode. -+ */ -+ radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) | -+ (freq ? 0x10 : 0); -+ radio->buffer[6] = 0x00; -+ radio->buffer[7] = 0x00; -+ -+ ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), -+ 9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); -+ -+ if (ret < 0) { -+ dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret); -+ return ret; -+ } -+ if (freq) -+ radio->curfreq = freq; -+ return 0; -+} -+ -+/* Set TX, stereo and preemphasis mode (50 us vs 75 us). */ -+static int keene_cmd_set(struct keene_device *radio) -+{ -+ int ret; -+ -+ radio->buffer[0] = 0x00; -+ radio->buffer[1] = 0x51; -+ radio->buffer[2] = radio->tx; -+ /* If bit 0 is set, then transmit mono, otherwise stereo. -+ If bit 2 is set, then enable 75 us preemphasis, otherwise -+ it is 50 us. */ -+ radio->buffer[3] = (!radio->stereo) | (radio->preemph_75_us ? 4 : 0); -+ radio->buffer[4] = 0x00; -+ radio->buffer[5] = 0x00; -+ radio->buffer[6] = 0x00; -+ radio->buffer[7] = 0x00; -+ -+ ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), -+ 9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT); -+ -+ if (ret < 0) { -+ dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret); -+ return ret; -+ } -+ return 0; -+} -+ -+/* Handle unplugging the device. -+ * We call video_unregister_device in any case. -+ * The last function called in this procedure is -+ * usb_keene_device_release. -+ */ -+static void usb_keene_disconnect(struct usb_interface *intf) -+{ -+ struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf)); -+ -+ v4l2_device_get(&radio->v4l2_dev); -+ mutex_lock(&radio->lock); -+ usb_set_intfdata(intf, NULL); -+ video_unregister_device(&radio->vdev); -+ v4l2_device_disconnect(&radio->v4l2_dev); -+ mutex_unlock(&radio->lock); -+ v4l2_device_put(&radio->v4l2_dev); -+} -+ -+static int vidioc_querycap(struct file *file, void *priv, -+ struct v4l2_capability *v) -+{ -+ struct keene_device *radio = video_drvdata(file); -+ -+ strlcpy(v->driver, "radio-keene", sizeof(v->driver)); -+ strlcpy(v->card, "Keene FM Transmitter", sizeof(v->card)); -+ usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); -+ v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR; -+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; -+ return 0; -+} -+ -+static int vidioc_g_modulator(struct file *file, void *priv, -+ struct v4l2_modulator *v) -+{ -+ struct keene_device *radio = video_drvdata(file); -+ -+ if (v->index > 0) -+ return -EINVAL; -+ -+ strlcpy(v->name, "FM", sizeof(v->name)); -+ v->rangelow = FREQ_MIN * FREQ_MUL; -+ v->rangehigh = FREQ_MAX * FREQ_MUL; -+ v->txsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; -+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; -+ return 0; -+} -+ -+static int vidioc_s_modulator(struct file *file, void *priv, -+ struct v4l2_modulator *v) -+{ -+ struct keene_device *radio = video_drvdata(file); -+ -+ if (v->index > 0) -+ return -EINVAL; -+ -+ radio->stereo = (v->txsubchans == V4L2_TUNER_SUB_STEREO); -+ return keene_cmd_set(radio); -+} -+ -+static int vidioc_s_frequency(struct file *file, void *priv, -+ struct v4l2_frequency *f) -+{ -+ struct keene_device *radio = video_drvdata(file); -+ -+ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -+ return -EINVAL; -+ f->frequency = clamp(f->frequency, -+ FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); -+ return keene_cmd_main(radio, f->frequency, true); -+} -+ -+static int vidioc_g_frequency(struct file *file, void *priv, -+ struct v4l2_frequency *f) -+{ -+ struct keene_device *radio = video_drvdata(file); -+ -+ if (f->tuner != 0) -+ return -EINVAL; -+ f->type = V4L2_TUNER_RADIO; -+ f->frequency = radio->curfreq; -+ return 0; -+} -+ -+static int keene_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ static const u8 db2tx[] = { -+ /* -15, -12, -9, -6, -3, 0 dB */ -+ 0x03, 0x13, 0x02, 0x12, 0x22, 0x32, -+ /* 3, 6, 9, 12, 15, 18 dB */ -+ 0x21, 0x31, 0x20, 0x30, 0x40, 0x50 -+ }; -+ struct keene_device *radio = -+ container_of(ctrl->handler, struct keene_device, hdl); -+ -+ switch (ctrl->id) { -+ case V4L2_CID_AUDIO_MUTE: -+ radio->muted = ctrl->val; -+ return keene_cmd_main(radio, 0, true); -+ -+ case V4L2_CID_TUNE_POWER_LEVEL: -+ /* To go from dBuV to the register value we apply the -+ following formula: */ -+ radio->pa = (ctrl->val - 71) * 100 / 62; -+ return keene_cmd_main(radio, 0, true); -+ -+ case V4L2_CID_TUNE_PREEMPHASIS: -+ radio->preemph_75_us = ctrl->val == V4L2_PREEMPHASIS_75_uS; -+ return keene_cmd_set(radio); -+ -+ case V4L2_CID_AUDIO_COMPRESSION_GAIN: -+ radio->tx = db2tx[(ctrl->val - ctrl->minimum) / ctrl->step]; -+ return keene_cmd_set(radio); -+ } -+ return -EINVAL; -+} -+ -+static int vidioc_subscribe_event(struct v4l2_fh *fh, -+ struct v4l2_event_subscription *sub) -+{ -+ switch (sub->type) { -+ case V4L2_EVENT_CTRL: -+ return v4l2_event_subscribe(fh, sub, 0); -+ default: -+ return -EINVAL; -+ } -+} -+ -+ -+/* File system interface */ -+static const struct v4l2_file_operations usb_keene_fops = { -+ .owner = THIS_MODULE, -+ .open = v4l2_fh_open, -+ .release = v4l2_fh_release, -+ .poll = v4l2_ctrl_poll, -+ .unlocked_ioctl = video_ioctl2, -+}; -+ -+static const struct v4l2_ctrl_ops keene_ctrl_ops = { -+ .s_ctrl = keene_s_ctrl, -+}; -+ -+static const struct v4l2_ioctl_ops usb_keene_ioctl_ops = { -+ .vidioc_querycap = vidioc_querycap, -+ .vidioc_g_modulator = vidioc_g_modulator, -+ .vidioc_s_modulator = vidioc_s_modulator, -+ .vidioc_g_frequency = vidioc_g_frequency, -+ .vidioc_s_frequency = vidioc_s_frequency, -+ .vidioc_log_status = v4l2_ctrl_log_status, -+ .vidioc_subscribe_event = vidioc_subscribe_event, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -+}; -+ -+static void usb_keene_video_device_release(struct v4l2_device *v4l2_dev) -+{ -+ struct keene_device *radio = to_keene_dev(v4l2_dev); -+ -+ /* free rest memory */ -+ v4l2_ctrl_handler_free(&radio->hdl); -+ kfree(radio->buffer); -+ kfree(radio); -+} -+ -+/* check if the device is present and register with v4l and usb if it is */ -+static int usb_keene_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct keene_device *radio; -+ struct v4l2_ctrl_handler *hdl; -+ int retval = 0; -+ -+ /* -+ * The Keene FM transmitter USB device has the same USB ID as -+ * the Logitech AudioHub Speaker, but it should ignore the hid. -+ * Check if the name is that of the Keene device. -+ * If not, then someone connected the AudioHub and we shouldn't -+ * attempt to handle this driver. -+ * For reference: the product name of the AudioHub is -+ * "AudioHub Speaker". -+ */ -+ if (dev->product && strcmp(dev->product, "B-LINK USB Audio ")) -+ return -ENODEV; -+ -+ radio = kzalloc(sizeof(struct keene_device), GFP_KERNEL); -+ if (radio) -+ radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); -+ -+ if (!radio || !radio->buffer) { -+ dev_err(&intf->dev, "kmalloc for keene_device failed\n"); -+ kfree(radio); -+ retval = -ENOMEM; -+ goto err; -+ } -+ -+ hdl = &radio->hdl; -+ v4l2_ctrl_handler_init(hdl, 4); -+ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_MUTE, -+ 0, 1, 1, 0); -+ v4l2_ctrl_new_std_menu(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS, -+ V4L2_PREEMPHASIS_75_uS, 1, V4L2_PREEMPHASIS_50_uS); -+ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_POWER_LEVEL, -+ 84, 118, 1, 118); -+ v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_COMPRESSION_GAIN, -+ -15, 18, 3, 0); -+ radio->pa = 118; -+ radio->tx = 0x32; -+ radio->stereo = true; -+ radio->curfreq = 95.16 * FREQ_MUL; -+ if (hdl->error) { -+ retval = hdl->error; -+ -+ v4l2_ctrl_handler_free(hdl); -+ goto err_v4l2; -+ } -+ retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); -+ if (retval < 0) { -+ dev_err(&intf->dev, "couldn't register v4l2_device\n"); -+ goto err_v4l2; -+ } -+ -+ mutex_init(&radio->lock); -+ -+ radio->v4l2_dev.ctrl_handler = hdl; -+ radio->v4l2_dev.release = usb_keene_video_device_release; -+ strlcpy(radio->vdev.name, radio->v4l2_dev.name, -+ sizeof(radio->vdev.name)); -+ radio->vdev.v4l2_dev = &radio->v4l2_dev; -+ radio->vdev.fops = &usb_keene_fops; -+ radio->vdev.ioctl_ops = &usb_keene_ioctl_ops; -+ radio->vdev.lock = &radio->lock; -+ radio->vdev.release = video_device_release_empty; -+ -+ radio->usbdev = interface_to_usbdev(intf); -+ radio->intf = intf; -+ usb_set_intfdata(intf, &radio->v4l2_dev); -+ -+ video_set_drvdata(&radio->vdev, radio); -+ set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags); -+ -+ retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1); -+ if (retval < 0) { -+ dev_err(&intf->dev, "could not register video device\n"); -+ goto err_vdev; -+ } -+ v4l2_ctrl_handler_setup(hdl); -+ dev_info(&intf->dev, "V4L2 device registered as %s\n", -+ video_device_node_name(&radio->vdev)); -+ return 0; -+ -+err_vdev: -+ v4l2_device_unregister(&radio->v4l2_dev); -+err_v4l2: -+ kfree(radio->buffer); -+ kfree(radio); -+err: -+ return retval; -+} -+ -+/* USB subsystem interface */ -+static struct usb_driver usb_keene_driver = { -+ .name = "radio-keene", -+ .probe = usb_keene_probe, -+ .disconnect = usb_keene_disconnect, -+ .id_table = usb_keene_device_table, -+}; -+ -+static int __init keene_init(void) -+{ -+ int retval = usb_register(&usb_keene_driver); -+ -+ if (retval) -+ pr_err(KBUILD_MODNAME -+ ": usb_register failed. Error number %d\n", retval); -+ -+ return retval; -+} -+ -+static void __exit keene_exit(void) -+{ -+ usb_deregister(&usb_keene_driver); -+} -+ -+module_init(keene_init); -+module_exit(keene_exit); -+ -Index: linux-3.3.x86_64/drivers/media/rc/fintek-cir.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/fintek-cir.c -+++ linux-3.3.x86_64/drivers/media/rc/fintek-cir.c -@@ -117,7 +117,7 @@ static u8 fintek_cir_reg_read(struct fin - static void cir_dump_regs(struct fintek_dev *fintek) - { - fintek_config_mode_enable(fintek); -- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); -+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); - - pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME); - pr_reg(" * CR CIR BASE ADDR: 0x%x\n", -@@ -143,7 +143,7 @@ static int fintek_hw_detect(struct finte - u8 chip_major, chip_minor; - u8 vendor_major, vendor_minor; - u8 portsel, ir_class; -- u16 vendor; -+ u16 vendor, chip; - int ret = 0; - - fintek_config_mode_enable(fintek); -@@ -176,6 +176,7 @@ static int fintek_hw_detect(struct finte - - chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI); - chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO); -+ chip = chip_major << 8 | chip_minor; - - vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI); - vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO); -@@ -192,6 +193,15 @@ static int fintek_hw_detect(struct finte - fintek->chip_major = chip_major; - fintek->chip_minor = chip_minor; - fintek->chip_vendor = vendor; -+ -+ /* -+ * Newer reviews of this chipset uses port 8 instead of 5 -+ */ -+ if ((chip != 0x0408) || (chip != 0x0804)) -+ fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV2; -+ else -+ fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV1; -+ - spin_unlock_irqrestore(&fintek->fintek_lock, flags); - - return ret; -@@ -200,7 +210,7 @@ static int fintek_hw_detect(struct finte - static void fintek_cir_ldev_init(struct fintek_dev *fintek) - { - /* Select CIR logical device and enable */ -- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); -+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); - fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); - - /* Write allocated CIR address and IRQ information to hardware */ -@@ -381,7 +391,7 @@ static irqreturn_t fintek_cir_isr(int ir - fit_dbg_verbose("%s firing", __func__); - - fintek_config_mode_enable(fintek); -- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); -+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); - fintek_config_mode_disable(fintek); - - /* -@@ -422,7 +432,7 @@ static void fintek_enable_cir(struct fin - fintek_config_mode_enable(fintek); - - /* enable the CIR logical device */ -- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); -+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); - fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); - - fintek_config_mode_disable(fintek); -@@ -439,7 +449,7 @@ static void fintek_disable_cir(struct fi - fintek_config_mode_enable(fintek); - - /* disable the CIR logical device */ -- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); -+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); - fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); - - fintek_config_mode_disable(fintek); -@@ -611,7 +621,7 @@ static int fintek_suspend(struct pnp_dev - fintek_config_mode_enable(fintek); - - /* disable cir logical dev */ -- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); -+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); - fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); - - fintek_config_mode_disable(fintek); -@@ -634,7 +644,7 @@ static int fintek_resume(struct pnp_dev - - /* Enable CIR logical device */ - fintek_config_mode_enable(fintek); -- fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); -+ fintek_select_logical_dev(fintek, fintek->logical_dev_cir); - fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); - - fintek_config_mode_disable(fintek); -Index: linux-3.3.x86_64/drivers/media/rc/fintek-cir.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/fintek-cir.h -+++ linux-3.3.x86_64/drivers/media/rc/fintek-cir.h -@@ -88,6 +88,7 @@ struct fintek_dev { - u8 chip_major; - u8 chip_minor; - u16 chip_vendor; -+ u8 logical_dev_cir; - - /* hardware features */ - bool hw_learning_capable; -@@ -172,7 +173,8 @@ struct fintek_dev { - #define LOGICAL_DEV_ENABLE 0x01 - - /* Logical device number of the CIR function */ --#define LOGICAL_DEV_CIR 0x05 -+#define LOGICAL_DEV_CIR_REV1 0x05 -+#define LOGICAL_DEV_CIR_REV2 0x08 - - /* CIR Logical Device (LDN 0x08) config registers */ - #define CIR_CR_COMMAND_INDEX 0x04 -Index: linux-3.3.x86_64/drivers/media/radio/radio-isa.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/radio/radio-isa.c -@@ -0,0 +1,340 @@ -+/* -+ * Framework for ISA radio drivers. -+ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers -+ * to concentrate on the actual hardware operation. -+ * -+ * Copyright (C) 2012 Hans Verkuil -+ * -+ * 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. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "radio-isa.h" -+ -+MODULE_AUTHOR("Hans Verkuil"); -+MODULE_DESCRIPTION("A framework for ISA radio drivers."); -+MODULE_LICENSE("GPL"); -+ -+#define FREQ_LOW (87U * 16000U) -+#define FREQ_HIGH (108U * 16000U) -+ -+static int radio_isa_querycap(struct file *file, void *priv, -+ struct v4l2_capability *v) -+{ -+ struct radio_isa_card *isa = video_drvdata(file); -+ -+ strlcpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver)); -+ strlcpy(v->card, isa->drv->card, sizeof(v->card)); -+ snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); -+ -+ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -+ v->device_caps = v->capabilities | V4L2_CAP_DEVICE_CAPS; -+ return 0; -+} -+ -+static int radio_isa_g_tuner(struct file *file, void *priv, -+ struct v4l2_tuner *v) -+{ -+ struct radio_isa_card *isa = video_drvdata(file); -+ const struct radio_isa_ops *ops = isa->drv->ops; -+ -+ if (v->index > 0) -+ return -EINVAL; -+ -+ strlcpy(v->name, "FM", sizeof(v->name)); -+ v->type = V4L2_TUNER_RADIO; -+ v->rangelow = FREQ_LOW; -+ v->rangehigh = FREQ_HIGH; -+ v->capability = V4L2_TUNER_CAP_LOW; -+ if (isa->drv->has_stereo) -+ v->capability |= V4L2_TUNER_CAP_STEREO; -+ -+ if (ops->g_rxsubchans) -+ v->rxsubchans = ops->g_rxsubchans(isa); -+ else -+ v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; -+ v->audmode = isa->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; -+ if (ops->g_signal) -+ v->signal = ops->g_signal(isa); -+ else -+ v->signal = (v->rxsubchans & V4L2_TUNER_SUB_STEREO) ? -+ 0xffff : 0; -+ return 0; -+} -+ -+static int radio_isa_s_tuner(struct file *file, void *priv, -+ struct v4l2_tuner *v) -+{ -+ struct radio_isa_card *isa = video_drvdata(file); -+ const struct radio_isa_ops *ops = isa->drv->ops; -+ -+ if (v->index) -+ return -EINVAL; -+ if (ops->s_stereo) { -+ isa->stereo = (v->audmode == V4L2_TUNER_MODE_STEREO); -+ return ops->s_stereo(isa, isa->stereo); -+ } -+ return 0; -+} -+ -+static int radio_isa_s_frequency(struct file *file, void *priv, -+ struct v4l2_frequency *f) -+{ -+ struct radio_isa_card *isa = video_drvdata(file); -+ int res; -+ -+ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -+ return -EINVAL; -+ f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH); -+ res = isa->drv->ops->s_frequency(isa, f->frequency); -+ if (res == 0) -+ isa->freq = f->frequency; -+ return res; -+} -+ -+static int radio_isa_g_frequency(struct file *file, void *priv, -+ struct v4l2_frequency *f) -+{ -+ struct radio_isa_card *isa = video_drvdata(file); -+ -+ if (f->tuner != 0) -+ return -EINVAL; -+ f->type = V4L2_TUNER_RADIO; -+ f->frequency = isa->freq; -+ return 0; -+} -+ -+static int radio_isa_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct radio_isa_card *isa = -+ container_of(ctrl->handler, struct radio_isa_card, hdl); -+ -+ switch (ctrl->id) { -+ case V4L2_CID_AUDIO_MUTE: -+ return isa->drv->ops->s_mute_volume(isa, ctrl->val, -+ isa->volume ? isa->volume->val : 0); -+ } -+ return -EINVAL; -+} -+ -+static int radio_isa_log_status(struct file *file, void *priv) -+{ -+ struct radio_isa_card *isa = video_drvdata(file); -+ -+ v4l2_info(&isa->v4l2_dev, "I/O Port = 0x%03x\n", isa->io); -+ v4l2_ctrl_handler_log_status(&isa->hdl, isa->v4l2_dev.name); -+ return 0; -+} -+ -+static int radio_isa_subscribe_event(struct v4l2_fh *fh, -+ struct v4l2_event_subscription *sub) -+{ -+ if (sub->type == V4L2_EVENT_CTRL) -+ return v4l2_event_subscribe(fh, sub, 0); -+ return -EINVAL; -+} -+ -+static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = { -+ .s_ctrl = radio_isa_s_ctrl, -+}; -+ -+static const struct v4l2_file_operations radio_isa_fops = { -+ .owner = THIS_MODULE, -+ .open = v4l2_fh_open, -+ .release = v4l2_fh_release, -+ .poll = v4l2_ctrl_poll, -+ .unlocked_ioctl = video_ioctl2, -+}; -+ -+static const struct v4l2_ioctl_ops radio_isa_ioctl_ops = { -+ .vidioc_querycap = radio_isa_querycap, -+ .vidioc_g_tuner = radio_isa_g_tuner, -+ .vidioc_s_tuner = radio_isa_s_tuner, -+ .vidioc_g_frequency = radio_isa_g_frequency, -+ .vidioc_s_frequency = radio_isa_s_frequency, -+ .vidioc_log_status = radio_isa_log_status, -+ .vidioc_subscribe_event = radio_isa_subscribe_event, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -+}; -+ -+int radio_isa_match(struct device *pdev, unsigned int dev) -+{ -+ struct radio_isa_driver *drv = pdev->platform_data; -+ -+ return drv->probe || drv->io_params[dev] >= 0; -+} -+EXPORT_SYMBOL_GPL(radio_isa_match); -+ -+static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io) -+{ -+ int i; -+ -+ for (i = 0; i < drv->num_of_io_ports; i++) -+ if (drv->io_ports[i] == io) -+ return true; -+ return false; -+} -+ -+int radio_isa_probe(struct device *pdev, unsigned int dev) -+{ -+ struct radio_isa_driver *drv = pdev->platform_data; -+ const struct radio_isa_ops *ops = drv->ops; -+ struct v4l2_device *v4l2_dev; -+ struct radio_isa_card *isa; -+ int res; -+ -+ isa = drv->ops->alloc(); -+ if (isa == NULL) -+ return -ENOMEM; -+ dev_set_drvdata(pdev, isa); -+ isa->drv = drv; -+ isa->io = drv->io_params[dev]; -+ v4l2_dev = &isa->v4l2_dev; -+ strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name)); -+ -+ if (drv->probe && ops->probe) { -+ int i; -+ -+ for (i = 0; i < drv->num_of_io_ports; ++i) { -+ int io = drv->io_ports[i]; -+ -+ if (request_region(io, drv->region_size, v4l2_dev->name)) { -+ bool found = ops->probe(isa, io); -+ -+ release_region(io, drv->region_size); -+ if (found) { -+ isa->io = io; -+ break; -+ } -+ } -+ } -+ } -+ -+ if (!radio_isa_valid_io(drv, isa->io)) { -+ int i; -+ -+ if (isa->io < 0) -+ return -ENODEV; -+ v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x", -+ drv->io_ports[0]); -+ for (i = 1; i < drv->num_of_io_ports; i++) -+ printk(KERN_CONT "/0x%03x", drv->io_ports[i]); -+ printk(KERN_CONT ".\n"); -+ kfree(isa); -+ return -EINVAL; -+ } -+ -+ if (!request_region(isa->io, drv->region_size, v4l2_dev->name)) { -+ v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io); -+ kfree(isa); -+ return -EBUSY; -+ } -+ -+ res = v4l2_device_register(pdev, v4l2_dev); -+ if (res < 0) { -+ v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); -+ goto err_dev_reg; -+ } -+ -+ v4l2_ctrl_handler_init(&isa->hdl, 1); -+ isa->mute = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops, -+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); -+ if (drv->max_volume) -+ isa->volume = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops, -+ V4L2_CID_AUDIO_VOLUME, 0, drv->max_volume, 1, -+ drv->max_volume); -+ v4l2_dev->ctrl_handler = &isa->hdl; -+ if (isa->hdl.error) { -+ res = isa->hdl.error; -+ v4l2_err(v4l2_dev, "Could not register controls\n"); -+ goto err_hdl; -+ } -+ if (drv->max_volume) -+ v4l2_ctrl_cluster(2, &isa->mute); -+ v4l2_dev->ctrl_handler = &isa->hdl; -+ -+ mutex_init(&isa->lock); -+ isa->vdev.lock = &isa->lock; -+ strlcpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name)); -+ isa->vdev.v4l2_dev = v4l2_dev; -+ isa->vdev.fops = &radio_isa_fops; -+ isa->vdev.ioctl_ops = &radio_isa_ioctl_ops; -+ isa->vdev.release = video_device_release_empty; -+ set_bit(V4L2_FL_USE_FH_PRIO, &isa->vdev.flags); -+ video_set_drvdata(&isa->vdev, isa); -+ isa->freq = FREQ_LOW; -+ isa->stereo = drv->has_stereo; -+ -+ if (ops->init) -+ res = ops->init(isa); -+ if (!res) -+ res = v4l2_ctrl_handler_setup(&isa->hdl); -+ if (!res) -+ res = ops->s_frequency(isa, isa->freq); -+ if (!res && ops->s_stereo) -+ res = ops->s_stereo(isa, isa->stereo); -+ if (res < 0) { -+ v4l2_err(v4l2_dev, "Could not setup card\n"); -+ goto err_node_reg; -+ } -+ res = video_register_device(&isa->vdev, VFL_TYPE_RADIO, -+ drv->radio_nr_params[dev]); -+ if (res < 0) { -+ v4l2_err(v4l2_dev, "Could not register device node\n"); -+ goto err_node_reg; -+ } -+ -+ v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n", -+ drv->card, isa->io); -+ return 0; -+ -+err_node_reg: -+ v4l2_ctrl_handler_free(&isa->hdl); -+err_hdl: -+ v4l2_device_unregister(&isa->v4l2_dev); -+err_dev_reg: -+ release_region(isa->io, drv->region_size); -+ kfree(isa); -+ return res; -+} -+EXPORT_SYMBOL_GPL(radio_isa_probe); -+ -+int radio_isa_remove(struct device *pdev, unsigned int dev) -+{ -+ struct radio_isa_card *isa = dev_get_drvdata(pdev); -+ const struct radio_isa_ops *ops = isa->drv->ops; -+ -+ ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0); -+ video_unregister_device(&isa->vdev); -+ v4l2_ctrl_handler_free(&isa->hdl); -+ v4l2_device_unregister(&isa->v4l2_dev); -+ release_region(isa->io, isa->drv->region_size); -+ v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card); -+ kfree(isa); -+ return 0; -+} -+EXPORT_SYMBOL_GPL(radio_isa_remove); -Index: linux-3.3.x86_64/drivers/media/radio/radio-isa.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/radio/radio-isa.h -@@ -0,0 +1,105 @@ -+/* -+ * Framework for ISA radio drivers. -+ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers -+ * to concentrate on the actual hardware operation. -+ * -+ * Copyright (C) 2012 Hans Verkuil -+ * -+ * 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. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ */ -+ -+#ifndef _RADIO_ISA_H_ -+#define _RADIO_ISA_H_ -+ -+#include -+#include -+#include -+#include -+ -+struct radio_isa_driver; -+struct radio_isa_ops; -+ -+/* Core structure for radio ISA cards */ -+struct radio_isa_card { -+ const struct radio_isa_driver *drv; -+ struct v4l2_device v4l2_dev; -+ struct v4l2_ctrl_handler hdl; -+ struct video_device vdev; -+ struct mutex lock; -+ const struct radio_isa_ops *ops; -+ struct { /* mute/volume cluster */ -+ struct v4l2_ctrl *mute; -+ struct v4l2_ctrl *volume; -+ }; -+ /* I/O port */ -+ int io; -+ -+ /* Card is in stereo audio mode */ -+ bool stereo; -+ /* Current frequency */ -+ u32 freq; -+}; -+ -+struct radio_isa_ops { -+ /* Allocate and initialize a radio_isa_card struct */ -+ struct radio_isa_card *(*alloc)(void); -+ /* Probe whether a card is present at the given port */ -+ bool (*probe)(struct radio_isa_card *isa, int io); -+ /* Special card initialization can be done here, this is called after -+ * the standard controls are registered, but before they are setup, -+ * thus allowing drivers to add their own controls here. */ -+ int (*init)(struct radio_isa_card *isa); -+ /* Set mute and volume. */ -+ int (*s_mute_volume)(struct radio_isa_card *isa, bool mute, int volume); -+ /* Set frequency */ -+ int (*s_frequency)(struct radio_isa_card *isa, u32 freq); -+ /* Set stereo/mono audio mode */ -+ int (*s_stereo)(struct radio_isa_card *isa, bool stereo); -+ /* Get rxsubchans value for VIDIOC_G_TUNER */ -+ u32 (*g_rxsubchans)(struct radio_isa_card *isa); -+ /* Get the signal strength for VIDIOC_G_TUNER */ -+ u32 (*g_signal)(struct radio_isa_card *isa); -+}; -+ -+/* Top level structure needed to instantiate the cards */ -+struct radio_isa_driver { -+ struct isa_driver driver; -+ const struct radio_isa_ops *ops; -+ /* The module_param_array with the specified I/O ports */ -+ int *io_params; -+ /* The module_param_array with the radio_nr values */ -+ int *radio_nr_params; -+ /* Whether we should probe for possible cards */ -+ bool probe; -+ /* The list of possible I/O ports */ -+ const int *io_ports; -+ /* The size of that list */ -+ int num_of_io_ports; -+ /* The region size to request */ -+ unsigned region_size; -+ /* The name of the card */ -+ const char *card; -+ /* Card can capture stereo audio */ -+ bool has_stereo; -+ /* The maximum volume for the volume control. If 0, then there -+ is no volume control possible. */ -+ int max_volume; -+}; -+ -+int radio_isa_match(struct device *pdev, unsigned int dev); -+int radio_isa_probe(struct device *pdev, unsigned int dev); -+int radio_isa_remove(struct device *pdev, unsigned int dev); -+ -+#endif -Index: linux-3.3.x86_64/drivers/media/radio/radio-aimslab.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-aimslab.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-aimslab.c -@@ -1,16 +1,13 @@ --/* radiotrack (radioreveal) driver for Linux radio support -- * (c) 1997 M. Kirkwood -+/* -+ * AimsLab RadioTrack (aka RadioVeveal) driver -+ * -+ * Copyright 1997 M. Kirkwood -+ * -+ * Converted to the radio-isa framework by Hans Verkuil - * Converted to V4L2 API by Mauro Carvalho Chehab - * Converted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * -- * History: -- * 1999-02-24 Russell Kroll -- * Fine tuning/VIDEO_TUNER_LOW -- * Frequency range expanded to start at 87 MHz -- * -- * TODO: Allow for more than one of these foolish entities :-) -- * - * Notes on the hardware (reverse engineered from other peoples' - * reverse engineering of AIMS' code :-) - * -@@ -26,6 +23,7 @@ - * wait(a_wee_while); - * out(port, stop_changing_the_volume); - * -+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. - */ - - #include /* Modules */ -@@ -34,401 +32,179 @@ - #include /* msleep */ - #include /* kernel radio structs */ - #include /* outb, outb_p */ -+#include - #include - #include -+#include -+#include "radio-isa.h" - --MODULE_AUTHOR("M.Kirkwood"); -+MODULE_AUTHOR("M. Kirkwood"); - MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); - MODULE_LICENSE("GPL"); --MODULE_VERSION("0.0.3"); -+MODULE_VERSION("1.0.0"); - - #ifndef CONFIG_RADIO_RTRACK_PORT - #define CONFIG_RADIO_RTRACK_PORT -1 - #endif - --static int io = CONFIG_RADIO_RTRACK_PORT; --static int radio_nr = -1; -+#define RTRACK_MAX 2 - --module_param(io, int, 0); --MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); --module_param(radio_nr, int, 0); -+static int io[RTRACK_MAX] = { [0] = CONFIG_RADIO_RTRACK_PORT, -+ [1 ... (RTRACK_MAX - 1)] = -1 }; -+static int radio_nr[RTRACK_MAX] = { [0 ... (RTRACK_MAX - 1)] = -1 }; -+ -+module_param_array(io, int, NULL, 0444); -+MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)"); -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); - --struct rtrack --{ -- struct v4l2_device v4l2_dev; -- struct video_device vdev; -- int port; -+struct rtrack { -+ struct radio_isa_card isa; - int curvol; -- unsigned long curfreq; -- int muted; -- int io; -- struct mutex lock; - }; - --static struct rtrack rtrack_card; -- --/* local things */ -- --static void rt_decvol(struct rtrack *rt) --{ -- outb(0x58, rt->io); /* volume down + sigstr + on */ -- msleep(100); -- outb(0xd8, rt->io); /* volume steady + sigstr + on */ --} -- --static void rt_incvol(struct rtrack *rt) --{ -- outb(0x98, rt->io); /* volume up + sigstr + on */ -- msleep(100); -- outb(0xd8, rt->io); /* volume steady + sigstr + on */ --} -- --static void rt_mute(struct rtrack *rt) --{ -- rt->muted = 1; -- mutex_lock(&rt->lock); -- outb(0xd0, rt->io); /* volume steady, off */ -- mutex_unlock(&rt->lock); --} -- --static int rt_setvol(struct rtrack *rt, int vol) -+static struct radio_isa_card *rtrack_alloc(void) - { -- int i; -- -- mutex_lock(&rt->lock); -- -- if (vol == rt->curvol) { /* requested volume = current */ -- if (rt->muted) { /* user is unmuting the card */ -- rt->muted = 0; -- outb(0xd8, rt->io); /* enable card */ -- } -- mutex_unlock(&rt->lock); -- return 0; -- } -- -- if (vol == 0) { /* volume = 0 means mute the card */ -- outb(0x48, rt->io); /* volume down but still "on" */ -- msleep(2000); /* make sure it's totally down */ -- outb(0xd0, rt->io); /* volume steady, off */ -- rt->curvol = 0; /* track the volume state! */ -- mutex_unlock(&rt->lock); -- return 0; -- } -- -- rt->muted = 0; -- if (vol > rt->curvol) -- for (i = rt->curvol; i < vol; i++) -- rt_incvol(rt); -- else -- for (i = rt->curvol; i > vol; i--) -- rt_decvol(rt); -+ struct rtrack *rt = kzalloc(sizeof(struct rtrack), GFP_KERNEL); - -- rt->curvol = vol; -- mutex_unlock(&rt->lock); -- return 0; -+ if (rt) -+ rt->curvol = 0xff; -+ return rt ? &rt->isa : NULL; - } - --/* the 128+64 on these outb's is to keep the volume stable while tuning -- * without them, the volume _will_ creep up with each frequency change -- * and bit 4 (+16) is to keep the signal strength meter enabled -+/* The 128+64 on these outb's is to keep the volume stable while tuning. -+ * Without them, the volume _will_ creep up with each frequency change -+ * and bit 4 (+16) is to keep the signal strength meter enabled. - */ - --static void send_0_byte(struct rtrack *rt) -+static void send_0_byte(struct radio_isa_card *isa, int on) - { -- if (rt->curvol == 0 || rt->muted) { -- outb_p(128+64+16+ 1, rt->io); /* wr-enable + data low */ -- outb_p(128+64+16+2+1, rt->io); /* clock */ -- } -- else { -- outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */ -- outb_p(128+64+16+8+2+1, rt->io); /* clock */ -- } -+ outb_p(128+64+16+on+1, isa->io); /* wr-enable + data low */ -+ outb_p(128+64+16+on+2+1, isa->io); /* clock */ - msleep(1); - } - --static void send_1_byte(struct rtrack *rt) -+static void send_1_byte(struct radio_isa_card *isa, int on) - { -- if (rt->curvol == 0 || rt->muted) { -- outb_p(128+64+16+4 +1, rt->io); /* wr-enable+data high */ -- outb_p(128+64+16+4+2+1, rt->io); /* clock */ -- } -- else { -- outb_p(128+64+16+8+4 +1, rt->io); /* on+wr-enable+data high */ -- outb_p(128+64+16+8+4+2+1, rt->io); /* clock */ -- } -- -+ outb_p(128+64+16+on+4+1, isa->io); /* wr-enable+data high */ -+ outb_p(128+64+16+on+4+2+1, isa->io); /* clock */ - msleep(1); - } - --static int rt_setfreq(struct rtrack *rt, unsigned long freq) -+static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq) - { -+ int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8; - int i; - -- mutex_lock(&rt->lock); /* Stop other ops interfering */ -- -- rt->curfreq = freq; -- -- /* now uses VIDEO_TUNER_LOW for fine tuning */ -- - freq += 171200; /* Add 10.7 MHz IF */ - freq /= 800; /* Convert to 50 kHz units */ - -- send_0_byte(rt); /* 0: LSB of frequency */ -+ send_0_byte(isa, on); /* 0: LSB of frequency */ - - for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ - if (freq & (1 << i)) -- send_1_byte(rt); -+ send_1_byte(isa, on); - else -- send_0_byte(rt); -+ send_0_byte(isa, on); - -- send_0_byte(rt); /* 14: test bit - always 0 */ -- send_0_byte(rt); /* 15: test bit - always 0 */ -+ send_0_byte(isa, on); /* 14: test bit - always 0 */ -+ send_0_byte(isa, on); /* 15: test bit - always 0 */ - -- send_0_byte(rt); /* 16: band data 0 - always 0 */ -- send_0_byte(rt); /* 17: band data 1 - always 0 */ -- send_0_byte(rt); /* 18: band data 2 - always 0 */ -- send_0_byte(rt); /* 19: time base - always 0 */ -- -- send_0_byte(rt); /* 20: spacing (0 = 25 kHz) */ -- send_1_byte(rt); /* 21: spacing (1 = 25 kHz) */ -- send_0_byte(rt); /* 22: spacing (0 = 25 kHz) */ -- send_1_byte(rt); /* 23: AM/FM (FM = 1, always) */ -- -- if (rt->curvol == 0 || rt->muted) -- outb(0xd0, rt->io); /* volume steady + sigstr */ -- else -- outb(0xd8, rt->io); /* volume steady + sigstr + on */ -+ send_0_byte(isa, on); /* 16: band data 0 - always 0 */ -+ send_0_byte(isa, on); /* 17: band data 1 - always 0 */ -+ send_0_byte(isa, on); /* 18: band data 2 - always 0 */ -+ send_0_byte(isa, on); /* 19: time base - always 0 */ - -- mutex_unlock(&rt->lock); -+ send_0_byte(isa, on); /* 20: spacing (0 = 25 kHz) */ -+ send_1_byte(isa, on); /* 21: spacing (1 = 25 kHz) */ -+ send_0_byte(isa, on); /* 22: spacing (0 = 25 kHz) */ -+ send_1_byte(isa, on); /* 23: AM/FM (FM = 1, always) */ - -+ outb(0xd0 + on, isa->io); /* volume steady + sigstr */ - return 0; - } - --static int rt_getsigstr(struct rtrack *rt) -+static u32 rtrack_g_signal(struct radio_isa_card *isa) - { -- int sig = 1; -- -- mutex_lock(&rt->lock); -- if (inb(rt->io) & 2) /* bit set = no signal present */ -- sig = 0; -- mutex_unlock(&rt->lock); -- return sig; --} -- --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); -- strlcpy(v->card, "RadioTrack", sizeof(v->card)); -- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -- return 0; --} -- --static int vidioc_g_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- struct rtrack *rt = video_drvdata(file); -- -- if (v->index > 0) -- return -EINVAL; -- -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- v->rangelow = 87 * 16000; -- v->rangehigh = 108 * 16000; -- v->rxsubchans = V4L2_TUNER_SUB_MONO; -- v->capability = V4L2_TUNER_CAP_LOW; -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->signal = 0xffff * rt_getsigstr(rt); -- return 0; -+ /* bit set = no signal present */ -+ return 0xffff * !(inb(isa->io) & 2); - } - --static int vidioc_s_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) -+static int rtrack_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) - { -- return v->index ? -EINVAL : 0; --} -+ struct rtrack *rt = container_of(isa, struct rtrack, isa); -+ int curvol = rt->curvol; - --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct rtrack *rt = video_drvdata(file); -- -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- rt_setfreq(rt, f->frequency); -- return 0; --} -- --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct rtrack *rt = video_drvdata(file); -- -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = rt->curfreq; -- return 0; --} -- --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- switch (qc->id) { -- case V4L2_CID_AUDIO_MUTE: -- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); -- case V4L2_CID_AUDIO_VOLUME: -- return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); -- } -- return -EINVAL; --} -- --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct rtrack *rt = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- ctrl->value = rt->muted; -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- ctrl->value = rt->curvol; -+ if (mute) { -+ outb(0xd0, isa->io); /* volume steady + sigstr + off */ - return 0; - } -- return -EINVAL; --} -- --static int vidioc_s_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct rtrack *rt = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (ctrl->value) -- rt_mute(rt); -- else -- rt_setvol(rt, rt->curvol); -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- rt_setvol(rt, ctrl->value); -- return 0; -+ if (vol == 0) { /* volume = 0 means mute the card */ -+ outb(0x48, isa->io); /* volume down but still "on" */ -+ msleep(curvol * 3); /* make sure it's totally down */ -+ } else if (curvol < vol) { -+ outb(0x98, isa->io); /* volume up + sigstr + on */ -+ for (; curvol < vol; curvol++) -+ udelay(3000); -+ } else if (curvol > vol) { -+ outb(0x58, isa->io); /* volume down + sigstr + on */ -+ for (; curvol > vol; curvol--) -+ udelay(3000); - } -- return -EINVAL; --} -- --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; -+ outb(0xd8, isa->io); /* volume steady + sigstr + on */ -+ rt->curvol = vol; - return 0; - } - --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) --{ -- return i ? -EINVAL : 0; --} -- --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) -+/* Mute card - prevents noisy bootups */ -+static int rtrack_initialize(struct radio_isa_card *isa) - { -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -+ /* this ensures that the volume is all the way up */ -+ outb(0x90, isa->io); /* volume up but still "on" */ -+ msleep(3000); /* make sure it's totally up */ -+ outb(0xc0, isa->io); /* steady volume, mute card */ - return 0; - } - --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- return a->index ? -EINVAL : 0; --} -- --static const struct v4l2_file_operations rtrack_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, -+static const struct radio_isa_ops rtrack_ops = { -+ .alloc = rtrack_alloc, -+ .init = rtrack_initialize, -+ .s_mute_volume = rtrack_s_mute_volume, -+ .s_frequency = rtrack_s_frequency, -+ .g_signal = rtrack_g_signal, - }; - --static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl, -+static const int rtrack_ioports[] = { 0x20f, 0x30f }; -+ -+static struct radio_isa_driver rtrack_driver = { -+ .driver = { -+ .match = radio_isa_match, -+ .probe = radio_isa_probe, -+ .remove = radio_isa_remove, -+ .driver = { -+ .name = "radio-aimslab", -+ }, -+ }, -+ .io_params = io, -+ .radio_nr_params = radio_nr, -+ .io_ports = rtrack_ioports, -+ .num_of_io_ports = ARRAY_SIZE(rtrack_ioports), -+ .region_size = 2, -+ .card = "AIMSlab RadioTrack/RadioReveal", -+ .ops = &rtrack_ops, -+ .has_stereo = true, -+ .max_volume = 0xff, - }; - - static int __init rtrack_init(void) - { -- struct rtrack *rt = &rtrack_card; -- struct v4l2_device *v4l2_dev = &rt->v4l2_dev; -- int res; -- -- strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name)); -- rt->io = io; -- -- if (rt->io == -1) { -- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n"); -- return -EINVAL; -- } -- -- if (!request_region(rt->io, 2, "rtrack")) { -- v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io); -- return -EBUSY; -- } -- -- res = v4l2_device_register(NULL, v4l2_dev); -- if (res < 0) { -- release_region(rt->io, 2); -- v4l2_err(v4l2_dev, "could not register v4l2_device\n"); -- return res; -- } -- -- strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name)); -- rt->vdev.v4l2_dev = v4l2_dev; -- rt->vdev.fops = &rtrack_fops; -- rt->vdev.ioctl_ops = &rtrack_ioctl_ops; -- rt->vdev.release = video_device_release_empty; -- video_set_drvdata(&rt->vdev, rt); -- -- /* Set up the I/O locking */ -- -- mutex_init(&rt->lock); -- -- /* mute card - prevents noisy bootups */ -- -- /* this ensures that the volume is all the way down */ -- outb(0x48, rt->io); /* volume down but still "on" */ -- msleep(2000); /* make sure it's totally down */ -- outb(0xc0, rt->io); /* steady volume, mute card */ -- -- if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_device_unregister(&rt->v4l2_dev); -- release_region(rt->io, 2); -- return -EINVAL; -- } -- v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); -- -- return 0; -+ return isa_register_driver(&rtrack_driver.driver, RTRACK_MAX); - } - - static void __exit rtrack_exit(void) - { -- struct rtrack *rt = &rtrack_card; -- -- video_unregister_device(&rt->vdev); -- v4l2_device_unregister(&rt->v4l2_dev); -- release_region(rt->io, 2); -+ isa_unregister_driver(&rtrack_driver.driver); - } - - module_init(rtrack_init); - module_exit(rtrack_exit); -- -Index: linux-3.3.x86_64/drivers/media/radio/radio-aztech.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-aztech.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-aztech.c -@@ -1,5 +1,7 @@ --/* radio-aztech.c - Aztech radio card driver for Linux 2.2 -+/* -+ * radio-aztech.c - Aztech radio card driver - * -+ * Converted to the radio-isa framework by Hans Verkuil - * Converted to V4L2 API by Mauro Carvalho Chehab - * Adapted to support the Video for Linux API by - * Russell Kroll . Based on original tuner code by: -@@ -10,19 +12,7 @@ - * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) - * William McGrath (wmcgrath@twilight.vtc.vsc.edu) - * -- * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ -- * along with more information on the card itself. -- * -- * History: -- * 1999-02-24 Russell Kroll -- * Fine tuning/VIDEO_TUNER_LOW -- * Range expanded to 87-108 MHz (from 87.9-107.8) -- * -- * Notable changes from the original source: -- * - includes stripped down to the essentials -- * - for loops used as delays replaced with udelay() -- * - #defines removed, changed to static values -- * - tuning structure changed - no more character arrays, other changes -+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. - */ - - #include /* Modules */ -@@ -31,126 +21,72 @@ - #include /* udelay */ - #include /* kernel radio structs */ - #include /* outb, outb_p */ -+#include - #include - #include -+#include -+#include "radio-isa.h" - - MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); - MODULE_DESCRIPTION("A driver for the Aztech radio card."); - MODULE_LICENSE("GPL"); --MODULE_VERSION("0.0.3"); -+MODULE_VERSION("1.0.0"); - - /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ -- - #ifndef CONFIG_RADIO_AZTECH_PORT - #define CONFIG_RADIO_AZTECH_PORT -1 - #endif - --static int io = CONFIG_RADIO_AZTECH_PORT; --static int radio_nr = -1; --static int radio_wait_time = 1000; -- --module_param(io, int, 0); --module_param(radio_nr, int, 0); --MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); -+#define AZTECH_MAX 2 - --struct aztech --{ -- struct v4l2_device v4l2_dev; -- struct video_device vdev; -- int io; -+static int io[AZTECH_MAX] = { [0] = CONFIG_RADIO_AZTECH_PORT, -+ [1 ... (AZTECH_MAX - 1)] = -1 }; -+static int radio_nr[AZTECH_MAX] = { [0 ... (AZTECH_MAX - 1)] = -1 }; -+static const int radio_wait_time = 1000; -+ -+module_param_array(io, int, NULL, 0444); -+MODULE_PARM_DESC(io, "I/O addresses of the Aztech card (0x350 or 0x358)"); -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); -+ -+struct aztech { -+ struct radio_isa_card isa; - int curvol; -- unsigned long curfreq; -- int stereo; -- struct mutex lock; - }; - --static struct aztech aztech_card; -- --static int volconvert(int level) --{ -- level >>= 14; /* Map 16bits down to 2 bit */ -- level &= 3; -- -- /* convert to card-friendly values */ -- switch (level) { -- case 0: -- return 0; -- case 1: -- return 1; -- case 2: -- return 4; -- case 3: -- return 5; -- } -- return 0; /* Quieten gcc */ --} -- - static void send_0_byte(struct aztech *az) - { - udelay(radio_wait_time); -- outb_p(2 + volconvert(az->curvol), az->io); -- outb_p(64 + 2 + volconvert(az->curvol), az->io); -+ outb_p(2 + az->curvol, az->isa.io); -+ outb_p(64 + 2 + az->curvol, az->isa.io); - } - - static void send_1_byte(struct aztech *az) - { -- udelay (radio_wait_time); -- outb_p(128 + 2 + volconvert(az->curvol), az->io); -- outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io); --} -- --static int az_setvol(struct aztech *az, int vol) --{ -- mutex_lock(&az->lock); -- outb(volconvert(vol), az->io); -- mutex_unlock(&az->lock); -- return 0; --} -- --/* thanks to Michael Dwyer for giving me a dose of clues in -- * the signal strength department.. -- * -- * This card has a stereo bit - bit 0 set = mono, not set = stereo -- * It also has a "signal" bit - bit 1 set = bad signal, not set = good -- * -- */ -- --static int az_getsigstr(struct aztech *az) --{ -- int sig = 1; -- -- mutex_lock(&az->lock); -- if (inb(az->io) & 2) /* bit set = no signal present */ -- sig = 0; -- mutex_unlock(&az->lock); -- return sig; -+ udelay(radio_wait_time); -+ outb_p(128 + 2 + az->curvol, az->isa.io); -+ outb_p(128 + 64 + 2 + az->curvol, az->isa.io); - } - --static int az_getstereo(struct aztech *az) -+static struct radio_isa_card *aztech_alloc(void) - { -- int stereo = 1; -+ struct aztech *az = kzalloc(sizeof(*az), GFP_KERNEL); - -- mutex_lock(&az->lock); -- if (inb(az->io) & 1) /* bit set = mono */ -- stereo = 0; -- mutex_unlock(&az->lock); -- return stereo; -+ return az ? &az->isa : NULL; - } - --static int az_setfreq(struct aztech *az, unsigned long frequency) -+static int aztech_s_frequency(struct radio_isa_card *isa, u32 freq) - { -+ struct aztech *az = container_of(isa, struct aztech, isa); - int i; - -- mutex_lock(&az->lock); -- -- az->curfreq = frequency; -- frequency += 171200; /* Add 10.7 MHz IF */ -- frequency /= 800; /* Convert to 50 kHz units */ -+ freq += 171200; /* Add 10.7 MHz IF */ -+ freq /= 800; /* Convert to 50 kHz units */ - - send_0_byte(az); /* 0: LSB of frequency */ - - for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ -- if (frequency & (1 << i)) -+ if (freq & (1 << i)) - send_1_byte(az); - else - send_0_byte(az); -@@ -158,7 +94,7 @@ static int az_setfreq(struct aztech *az, - send_0_byte(az); /* 14: test bit - always 0 */ - send_0_byte(az); /* 15: test bit - always 0 */ - send_0_byte(az); /* 16: band data 0 - always 0 */ -- if (az->stereo) /* 17: stereo (1 to enable) */ -+ if (isa->stereo) /* 17: stereo (1 to enable) */ - send_1_byte(az); - else - send_0_byte(az); -@@ -173,225 +109,77 @@ static int az_setfreq(struct aztech *az, - /* latch frequency */ - - udelay(radio_wait_time); -- outb_p(128 + 64 + volconvert(az->curvol), az->io); -- -- mutex_unlock(&az->lock); -- -- return 0; --} -+ outb_p(128 + 64 + az->curvol, az->isa.io); - --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- strlcpy(v->driver, "radio-aztech", sizeof(v->driver)); -- strlcpy(v->card, "Aztech Radio", sizeof(v->card)); -- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - return 0; - } - --static int vidioc_g_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- struct aztech *az = video_drvdata(file); -- -- if (v->index > 0) -- return -EINVAL; -- -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- -- v->rangelow = 87 * 16000; -- v->rangehigh = 108 * 16000; -- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; -- v->capability = V4L2_TUNER_CAP_LOW; -- if (az_getstereo(az)) -- v->audmode = V4L2_TUNER_MODE_STEREO; -- else -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->signal = 0xFFFF * az_getsigstr(az); -- -- return 0; --} -- --static int vidioc_s_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- return v->index ? -EINVAL : 0; --} -- --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; -- return 0; --} -- --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) --{ -- return i ? -EINVAL : 0; --} -- --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) -+/* thanks to Michael Dwyer for giving me a dose of clues in -+ * the signal strength department.. -+ * -+ * This card has a stereo bit - bit 0 set = mono, not set = stereo -+ */ -+static u32 aztech_g_rxsubchans(struct radio_isa_card *isa) - { -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; -+ if (inb(isa->io) & 1) -+ return V4L2_TUNER_SUB_MONO; -+ return V4L2_TUNER_SUB_STEREO; - } - --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) -+static int aztech_s_stereo(struct radio_isa_card *isa, bool stereo) - { -- return a->index ? -EINVAL : 0; -+ return aztech_s_frequency(isa, isa->freq); - } - --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) -+static int aztech_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) - { -- struct aztech *az = video_drvdata(file); -+ struct aztech *az = container_of(isa, struct aztech, isa); - -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- az_setfreq(az, f->frequency); -+ if (mute) -+ vol = 0; -+ az->curvol = (vol & 1) + ((vol & 2) << 1); -+ outb(az->curvol, isa->io); - return 0; - } - --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct aztech *az = video_drvdata(file); -- -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = az->curfreq; -- return 0; --} -- --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- switch (qc->id) { -- case V4L2_CID_AUDIO_MUTE: -- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); -- case V4L2_CID_AUDIO_VOLUME: -- return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); -- } -- return -EINVAL; --} -- --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct aztech *az = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (az->curvol == 0) -- ctrl->value = 1; -- else -- ctrl->value = 0; -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- ctrl->value = az->curvol * 6554; -- return 0; -- } -- return -EINVAL; --} -- --static int vidioc_s_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct aztech *az = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (ctrl->value) -- az_setvol(az, 0); -- else -- az_setvol(az, az->curvol); -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- az_setvol(az, ctrl->value); -- return 0; -- } -- return -EINVAL; --} -- --static const struct v4l2_file_operations aztech_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, -+static const struct radio_isa_ops aztech_ops = { -+ .alloc = aztech_alloc, -+ .s_mute_volume = aztech_s_mute_volume, -+ .s_frequency = aztech_s_frequency, -+ .s_stereo = aztech_s_stereo, -+ .g_rxsubchans = aztech_g_rxsubchans, - }; - --static const struct v4l2_ioctl_ops aztech_ioctl_ops = { -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl, -+static const int aztech_ioports[] = { 0x350, 0x358 }; -+ -+static struct radio_isa_driver aztech_driver = { -+ .driver = { -+ .match = radio_isa_match, -+ .probe = radio_isa_probe, -+ .remove = radio_isa_remove, -+ .driver = { -+ .name = "radio-aztech", -+ }, -+ }, -+ .io_params = io, -+ .radio_nr_params = radio_nr, -+ .io_ports = aztech_ioports, -+ .num_of_io_ports = ARRAY_SIZE(aztech_ioports), -+ .region_size = 2, -+ .card = "Aztech Radio", -+ .ops = &aztech_ops, -+ .has_stereo = true, -+ .max_volume = 3, - }; - - static int __init aztech_init(void) - { -- struct aztech *az = &aztech_card; -- struct v4l2_device *v4l2_dev = &az->v4l2_dev; -- int res; -- -- strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name)); -- az->io = io; -- -- if (az->io == -1) { -- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n"); -- return -EINVAL; -- } -- -- if (!request_region(az->io, 2, "aztech")) { -- v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io); -- return -EBUSY; -- } -- -- res = v4l2_device_register(NULL, v4l2_dev); -- if (res < 0) { -- release_region(az->io, 2); -- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); -- return res; -- } -- -- mutex_init(&az->lock); -- strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name)); -- az->vdev.v4l2_dev = v4l2_dev; -- az->vdev.fops = &aztech_fops; -- az->vdev.ioctl_ops = &aztech_ioctl_ops; -- az->vdev.release = video_device_release_empty; -- video_set_drvdata(&az->vdev, az); -- /* mute card - prevents noisy bootups */ -- outb(0, az->io); -- -- if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_device_unregister(v4l2_dev); -- release_region(az->io, 2); -- return -EINVAL; -- } -- -- v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); -- return 0; -+ return isa_register_driver(&aztech_driver.driver, AZTECH_MAX); - } - - static void __exit aztech_exit(void) - { -- struct aztech *az = &aztech_card; -- -- video_unregister_device(&az->vdev); -- v4l2_device_unregister(&az->v4l2_dev); -- release_region(az->io, 2); -+ isa_unregister_driver(&aztech_driver.driver); - } - - module_init(aztech_init); -Index: linux-3.3.x86_64/drivers/media/radio/radio-gemtek.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-gemtek.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-gemtek.c -@@ -1,4 +1,7 @@ --/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin -+/* -+ * GemTek radio card driver -+ * -+ * Copyright 1998 Jonas Munsin - * - * GemTek hasn't released any specs on the card, so the protocol had to - * be reverse engineered with dosemu. -@@ -11,9 +14,12 @@ - * Converted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * -- * TODO: Allow for more than one of these foolish entities :-) -- * -+ * Converted to the radio-isa framework by Hans Verkuil - * Converted to V4L2 API by Mauro Carvalho Chehab -+ * -+ * Note: this card seems to swap the left and right audio channels! -+ * -+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. - */ - - #include /* Modules */ -@@ -23,8 +29,10 @@ - #include /* kernel radio structs */ - #include - #include /* outb, outb_p */ -+#include - #include - #include -+#include "radio-isa.h" - - /* - * Module info. -@@ -33,7 +41,7 @@ - MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen "); - MODULE_DESCRIPTION("A driver for the GemTek Radio card."); - MODULE_LICENSE("GPL"); --MODULE_VERSION("0.0.4"); -+MODULE_VERSION("1.0.0"); - - /* - * Module params. -@@ -46,45 +54,29 @@ MODULE_VERSION("0.0.4"); - #define CONFIG_RADIO_GEMTEK_PROBE 1 - #endif - --static int io = CONFIG_RADIO_GEMTEK_PORT; --static bool probe = CONFIG_RADIO_GEMTEK_PROBE; --static bool hardmute; --static bool shutdown = 1; --static bool keepmuted = 1; --static bool initmute = 1; --static int radio_nr = -1; -+#define GEMTEK_MAX 4 - --module_param(io, int, 0444); --MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " -- "probing is disabled or fails. The most common I/O ports are: 0x20c " -- "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " -- "work for the combined sound/radiocard)."); -+static bool probe = CONFIG_RADIO_GEMTEK_PROBE; -+static bool hardmute; -+static int io[GEMTEK_MAX] = { [0] = CONFIG_RADIO_GEMTEK_PORT, -+ [1 ... (GEMTEK_MAX - 1)] = -1 }; -+static int radio_nr[GEMTEK_MAX] = { [0 ... (GEMTEK_MAX - 1)] = -1 }; - - module_param(probe, bool, 0444); --MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " -- "common I/O ports used by the card are probed."); -+MODULE_PARM_DESC(probe, "Enable automatic device probing."); - - module_param(hardmute, bool, 0644); --MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may " -+MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may " - "reduce static noise."); - --module_param(shutdown, bool, 0644); --MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when " -- "module is unloaded."); -- --module_param(keepmuted, bool, 0644); --MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed."); -- --module_param(initmute, bool, 0444); --MODULE_PARM_DESC(initmute, "Mute card when module is loaded."); -- --module_param(radio_nr, int, 0444); -+module_param_array(io, int, NULL, 0444); -+MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic " -+ "probing is disabled or fails. The most common I/O ports are: 0x20c " -+ "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " -+ "work for the combined sound/radiocard)."); - --/* -- * Functions for controlling the card. -- */ --#define GEMTEK_LOWFREQ (87*16000) --#define GEMTEK_HIGHFREQ (108*16000) -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); - - /* - * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal -@@ -108,18 +100,11 @@ module_param(radio_nr, int, 0444); - #define LONG_DELAY 75 /* usec */ - - struct gemtek { -- struct v4l2_device v4l2_dev; -- struct video_device vdev; -- struct mutex lock; -- unsigned long lastfreq; -- int muted; -- int verified; -- int io; -+ struct radio_isa_card isa; -+ bool muted; - u32 bu2614data; - }; - --static struct gemtek gemtek_card; -- - #define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ - #define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ - #define BU2614_VOID_BITS 4 /* unused */ -@@ -166,31 +151,24 @@ static struct gemtek gemtek_card; - */ - static void gemtek_bu2614_transmit(struct gemtek *gt) - { -+ struct radio_isa_card *isa = >->isa; - int i, bit, q, mute; - -- mutex_lock(>->lock); -- - mute = gt->muted ? GEMTEK_MT : 0x00; - -- outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); -- udelay(SHORT_DELAY); -- outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); -+ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, isa->io); - udelay(LONG_DELAY); - - for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) { - bit = (q & 1) ? GEMTEK_DA : 0; -- outb_p(mute | GEMTEK_CE | bit, gt->io); -+ outb_p(mute | GEMTEK_CE | bit, isa->io); - udelay(SHORT_DELAY); -- outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io); -+ outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, isa->io); - udelay(SHORT_DELAY); - } - -- outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); -+ outb_p(mute | GEMTEK_DA | GEMTEK_CK, isa->io); - udelay(SHORT_DELAY); -- outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); -- udelay(LONG_DELAY); -- -- mutex_unlock(>->lock); - } - - /* -@@ -198,21 +176,27 @@ static void gemtek_bu2614_transmit(struc - */ - static unsigned long gemtek_convfreq(unsigned long freq) - { -- return ((freq<muted = true; -+ return gt ? >->isa : NULL; - } - - /* - * Set FM-frequency. - */ --static void gemtek_setfreq(struct gemtek *gt, unsigned long freq) -+static int gemtek_s_frequency(struct radio_isa_card *isa, u32 freq) - { -- if (keepmuted && hardmute && gt->muted) -- return; -+ struct gemtek *gt = container_of(isa, struct gemtek, isa); - -- freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ); -- -- gt->lastfreq = freq; -- gt->muted = 0; -+ if (hardmute && gt->muted) -+ return 0; - - gemtek_bu2614_set(gt, BU2614_PORT, 0); - gemtek_bu2614_set(gt, BU2614_FMES, 0); -@@ -220,23 +204,25 @@ static void gemtek_setfreq(struct gemtek - gemtek_bu2614_set(gt, BU2614_SWAL, 0); - gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */ - gemtek_bu2614_set(gt, BU2614_TEST, 0); -- - gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); - gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq)); -- - gemtek_bu2614_transmit(gt); -+ return 0; - } - - /* - * Set mute flag. - */ --static void gemtek_mute(struct gemtek *gt) -+static int gemtek_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) - { -+ struct gemtek *gt = container_of(isa, struct gemtek, isa); - int i; - -- gt->muted = 1; -- -+ gt->muted = mute; - if (hardmute) { -+ if (!mute) -+ return gemtek_s_frequency(isa, isa->freq); -+ - /* Turn off PLL, disable data output */ - gemtek_bu2614_set(gt, BU2614_PORT, 0); - gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */ -@@ -247,367 +233,85 @@ static void gemtek_mute(struct gemtek *g - gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF); - gemtek_bu2614_set(gt, BU2614_FREQ, 0); - gemtek_bu2614_transmit(gt); -- return; -+ return 0; - } - -- mutex_lock(>->lock); -- - /* Read bus contents (CE, CK and DA). */ -- i = inb_p(gt->io); -+ i = inb_p(isa->io); - /* Write it back with mute flag set. */ -- outb_p((i >> 5) | GEMTEK_MT, gt->io); -+ outb_p((i >> 5) | (mute ? GEMTEK_MT : 0), isa->io); - udelay(SHORT_DELAY); -- -- mutex_unlock(>->lock); --} -- --/* -- * Unset mute flag. -- */ --static void gemtek_unmute(struct gemtek *gt) --{ -- int i; -- -- gt->muted = 0; -- if (hardmute) { -- /* Turn PLL back on. */ -- gemtek_setfreq(gt, gt->lastfreq); -- return; -- } -- mutex_lock(>->lock); -- -- i = inb_p(gt->io); -- outb_p(i >> 5, gt->io); -- udelay(SHORT_DELAY); -- -- mutex_unlock(>->lock); -+ return 0; - } - --/* -- * Get signal strength (= stereo status). -- */ --static inline int gemtek_getsigstr(struct gemtek *gt) -+static u32 gemtek_g_rxsubchans(struct radio_isa_card *isa) - { -- int sig; -- -- mutex_lock(>->lock); -- sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1; -- mutex_unlock(>->lock); -- return sig; -+ if (inb_p(isa->io) & GEMTEK_NS) -+ return V4L2_TUNER_SUB_MONO; -+ return V4L2_TUNER_SUB_STEREO; - } - - /* - * Check if requested card acts like GemTek Radio card. - */ --static int gemtek_verify(struct gemtek *gt, int port) -+static bool gemtek_probe(struct radio_isa_card *isa, int io) - { - int i, q; - -- if (gt->verified == port) -- return 1; -- -- mutex_lock(>->lock); -- -- q = inb_p(port); /* Read bus contents before probing. */ -+ q = inb_p(io); /* Read bus contents before probing. */ - /* Try to turn on CE, CK and DA respectively and check if card responds - properly. */ - for (i = 0; i < 3; ++i) { -- outb_p(1 << i, port); -+ outb_p(1 << i, io); - udelay(SHORT_DELAY); - -- if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { -- mutex_unlock(>->lock); -- return 0; -- } -+ if ((inb_p(io) & ~GEMTEK_NS) != (0x17 | (1 << (i + 5)))) -+ return false; - } -- outb_p(q >> 5, port); /* Write bus contents back. */ -+ outb_p(q >> 5, io); /* Write bus contents back. */ - udelay(SHORT_DELAY); -- -- mutex_unlock(>->lock); -- gt->verified = port; -- -- return 1; --} -- --/* -- * Automatic probing for card. -- */ --static int gemtek_probe(struct gemtek *gt) --{ -- struct v4l2_device *v4l2_dev = >->v4l2_dev; -- int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; -- int i; -- -- if (!probe) { -- v4l2_info(v4l2_dev, "Automatic device probing disabled.\n"); -- return -1; -- } -- -- v4l2_info(v4l2_dev, "Automatic device probing enabled.\n"); -- -- for (i = 0; i < ARRAY_SIZE(ioports); ++i) { -- v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]); -- -- if (!request_region(ioports[i], 1, "gemtek-probe")) { -- v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n", -- ioports[i]); -- continue; -- } -- -- if (gemtek_verify(gt, ioports[i])) { -- v4l2_info(v4l2_dev, "Card found from I/O port " -- "0x%x!\n", ioports[i]); -- -- release_region(ioports[i], 1); -- gt->io = ioports[i]; -- return gt->io; -- } -- -- release_region(ioports[i], 1); -- } -- -- v4l2_err(v4l2_dev, "Automatic probing failed!\n"); -- return -1; -+ return true; - } - --/* -- * Video 4 Linux stuff. -- */ -- --static const struct v4l2_file_operations gemtek_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, -+static const struct radio_isa_ops gemtek_ops = { -+ .alloc = gemtek_alloc, -+ .probe = gemtek_probe, -+ .s_mute_volume = gemtek_s_mute_volume, -+ .s_frequency = gemtek_s_frequency, -+ .g_rxsubchans = gemtek_g_rxsubchans, - }; - --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); -- strlcpy(v->card, "GemTek", sizeof(v->card)); -- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -- return 0; --} -- --static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) --{ -- struct gemtek *gt = video_drvdata(file); -- -- if (v->index > 0) -- return -EINVAL; -- -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- v->rangelow = GEMTEK_LOWFREQ; -- v->rangehigh = GEMTEK_HIGHFREQ; -- v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; -- v->signal = 0xffff * gemtek_getsigstr(gt); -- if (v->signal) { -- v->audmode = V4L2_TUNER_MODE_STEREO; -- v->rxsubchans = V4L2_TUNER_SUB_STEREO; -- } else { -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->rxsubchans = V4L2_TUNER_SUB_MONO; -- } -- return 0; --} -- --static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) --{ -- return (v->index != 0) ? -EINVAL : 0; --} -- --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct gemtek *gt = video_drvdata(file); -- -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = gt->lastfreq; -- return 0; --} -- --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct gemtek *gt = video_drvdata(file); -- -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- gemtek_setfreq(gt, f->frequency); -- return 0; --} -- --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- switch (qc->id) { -- case V4L2_CID_AUDIO_MUTE: -- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); -- default: -- return -EINVAL; -- } --} -- --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct gemtek *gt = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- ctrl->value = gt->muted; -- return 0; -- } -- return -EINVAL; --} -+static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; - --static int vidioc_s_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct gemtek *gt = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (ctrl->value) -- gemtek_mute(gt); -- else -- gemtek_unmute(gt); -- return 0; -- } -- return -EINVAL; --} -- --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; -- return 0; --} -- --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) --{ -- return (i != 0) ? -EINVAL : 0; --} -- --static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) --{ -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; --} -- --static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) --{ -- return (a->index != 0) ? -EINVAL : 0; --} -- --static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl -+static struct radio_isa_driver gemtek_driver = { -+ .driver = { -+ .match = radio_isa_match, -+ .probe = radio_isa_probe, -+ .remove = radio_isa_remove, -+ .driver = { -+ .name = "radio-gemtek", -+ }, -+ }, -+ .io_params = io, -+ .radio_nr_params = radio_nr, -+ .io_ports = gemtek_ioports, -+ .num_of_io_ports = ARRAY_SIZE(gemtek_ioports), -+ .region_size = 1, -+ .card = "GemTek Radio", -+ .ops = &gemtek_ops, -+ .has_stereo = true, - }; - --/* -- * Initialization / cleanup related stuff. -- */ -- - static int __init gemtek_init(void) - { -- struct gemtek *gt = &gemtek_card; -- struct v4l2_device *v4l2_dev = >->v4l2_dev; -- int res; -- -- strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name)); -- -- v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n"); -- -- mutex_init(>->lock); -- -- gt->verified = -1; -- gt->io = io; -- gemtek_probe(gt); -- if (gt->io) { -- if (!request_region(gt->io, 1, "gemtek")) { -- v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io); -- return -EBUSY; -- } -- -- if (!gemtek_verify(gt, gt->io)) -- v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not " -- "respond properly, check your " -- "configuration.\n", gt->io); -- else -- v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io); -- } else if (probe) { -- v4l2_err(v4l2_dev, "Automatic probing failed and no " -- "fixed I/O port defined.\n"); -- return -ENODEV; -- } else { -- v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed " -- "I/O port defined."); -- return -EINVAL; -- } -- -- res = v4l2_device_register(NULL, v4l2_dev); -- if (res < 0) { -- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); -- release_region(gt->io, 1); -- return res; -- } -- -- strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name)); -- gt->vdev.v4l2_dev = v4l2_dev; -- gt->vdev.fops = &gemtek_fops; -- gt->vdev.ioctl_ops = &gemtek_ioctl_ops; -- gt->vdev.release = video_device_release_empty; -- video_set_drvdata(>->vdev, gt); -- -- /* Set defaults */ -- gt->lastfreq = GEMTEK_LOWFREQ; -- gt->bu2614data = 0; -- -- if (initmute) -- gemtek_mute(gt); -- -- if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_device_unregister(v4l2_dev); -- release_region(gt->io, 1); -- return -EBUSY; -- } -- -- return 0; -+ gemtek_driver.probe = probe; -+ return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX); - } - --/* -- * Module cleanup -- */ - static void __exit gemtek_exit(void) - { -- struct gemtek *gt = &gemtek_card; -- struct v4l2_device *v4l2_dev = >->v4l2_dev; -- -- if (shutdown) { -- hardmute = 1; /* Turn off PLL */ -- gemtek_mute(gt); -- } else { -- v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n"); -- } -- -- video_unregister_device(>->vdev); -- v4l2_device_unregister(>->v4l2_dev); -- release_region(gt->io, 1); -+ hardmute = 1; /* Turn off PLL */ -+ isa_unregister_driver(&gemtek_driver.driver); - } - - module_init(gemtek_init); -Index: linux-3.3.x86_64/drivers/media/radio/radio-rtrack2.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-rtrack2.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-rtrack2.c -@@ -1,11 +1,12 @@ --/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff -+/* -+ * RadioTrack II driver -+ * Copyright 1998 Ben Pfaff - * - * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood - * Converted to new API by Alan Cox - * Various bugfixes and enhancements by Russell Kroll - * -- * TODO: Allow for more than one of these foolish entities :-) -- * -+ * Converted to the radio-isa framework by Hans Verkuil - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -@@ -16,325 +17,123 @@ - #include /* kernel radio structs */ - #include - #include /* outb, outb_p */ -+#include - #include - #include -+#include "radio-isa.h" - - MODULE_AUTHOR("Ben Pfaff"); - MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); - MODULE_LICENSE("GPL"); --MODULE_VERSION("0.0.3"); -+MODULE_VERSION("0.1.99"); - - #ifndef CONFIG_RADIO_RTRACK2_PORT - #define CONFIG_RADIO_RTRACK2_PORT -1 - #endif - --static int io = CONFIG_RADIO_RTRACK2_PORT; --static int radio_nr = -1; -- --module_param(io, int, 0); --MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); --module_param(radio_nr, int, 0); -- --struct rtrack2 --{ -- struct v4l2_device v4l2_dev; -- struct video_device vdev; -- int io; -- unsigned long curfreq; -- int muted; -- struct mutex lock; --}; -- --static struct rtrack2 rtrack2_card; -+#define RTRACK2_MAX 2 - -+static int io[RTRACK2_MAX] = { [0] = CONFIG_RADIO_RTRACK2_PORT, -+ [1 ... (RTRACK2_MAX - 1)] = -1 }; -+static int radio_nr[RTRACK2_MAX] = { [0 ... (RTRACK2_MAX - 1)] = -1 }; - --/* local things */ -- --static void rt_mute(struct rtrack2 *dev) --{ -- if (dev->muted) -- return; -- mutex_lock(&dev->lock); -- outb(1, dev->io); -- mutex_unlock(&dev->lock); -- dev->muted = 1; --} -+module_param_array(io, int, NULL, 0444); -+MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)"); -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); - --static void rt_unmute(struct rtrack2 *dev) -+static struct radio_isa_card *rtrack2_alloc(void) - { -- if(dev->muted == 0) -- return; -- mutex_lock(&dev->lock); -- outb(0, dev->io); -- mutex_unlock(&dev->lock); -- dev->muted = 0; -+ return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL); - } - --static void zero(struct rtrack2 *dev) -+static void zero(struct radio_isa_card *isa) - { -- outb_p(1, dev->io); -- outb_p(3, dev->io); -- outb_p(1, dev->io); -+ outb_p(1, isa->io); -+ outb_p(3, isa->io); -+ outb_p(1, isa->io); - } - --static void one(struct rtrack2 *dev) -+static void one(struct radio_isa_card *isa) - { -- outb_p(5, dev->io); -- outb_p(7, dev->io); -- outb_p(5, dev->io); -+ outb_p(5, isa->io); -+ outb_p(7, isa->io); -+ outb_p(5, isa->io); - } - --static int rt_setfreq(struct rtrack2 *dev, unsigned long freq) -+static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq) - { - int i; - -- mutex_lock(&dev->lock); -- dev->curfreq = freq; - freq = freq / 200 + 856; - -- outb_p(0xc8, dev->io); -- outb_p(0xc9, dev->io); -- outb_p(0xc9, dev->io); -+ outb_p(0xc8, isa->io); -+ outb_p(0xc9, isa->io); -+ outb_p(0xc9, isa->io); - - for (i = 0; i < 10; i++) -- zero(dev); -+ zero(isa); - - for (i = 14; i >= 0; i--) - if (freq & (1 << i)) -- one(dev); -+ one(isa); - else -- zero(dev); -- -- outb_p(0xc8, dev->io); -- if (!dev->muted) -- outb_p(0, dev->io); -- -- mutex_unlock(&dev->lock); -- return 0; --} -- --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); -- strlcpy(v->card, "RadioTrack II", sizeof(v->card)); -- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -- return 0; --} -- --static int vidioc_s_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- return v->index ? -EINVAL : 0; --} -- --static int rt_getsigstr(struct rtrack2 *dev) --{ -- int sig = 1; -- -- mutex_lock(&dev->lock); -- if (inb(dev->io) & 2) /* bit set = no signal present */ -- sig = 0; -- mutex_unlock(&dev->lock); -- return sig; --} -+ zero(isa); - --static int vidioc_g_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- struct rtrack2 *rt = video_drvdata(file); -- -- if (v->index > 0) -- return -EINVAL; -- -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- v->rangelow = 88 * 16000; -- v->rangehigh = 108 * 16000; -- v->rxsubchans = V4L2_TUNER_SUB_MONO; -- v->capability = V4L2_TUNER_CAP_LOW; -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->signal = 0xFFFF * rt_getsigstr(rt); -+ outb_p(0xc8, isa->io); -+ if (!v4l2_ctrl_g_ctrl(isa->mute)) -+ outb_p(0, isa->io); - return 0; - } - --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) -+static u32 rtrack2_g_signal(struct radio_isa_card *isa) - { -- struct rtrack2 *rt = video_drvdata(file); -- -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- rt_setfreq(rt, f->frequency); -- return 0; -+ /* bit set = no signal present */ -+ return (inb(isa->io) & 2) ? 0 : 0xffff; - } - --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) -+static int rtrack2_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) - { -- struct rtrack2 *rt = video_drvdata(file); -- -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = rt->curfreq; -+ outb(mute, isa->io); - return 0; - } - --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- switch (qc->id) { -- case V4L2_CID_AUDIO_MUTE: -- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); -- case V4L2_CID_AUDIO_VOLUME: -- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535); -- } -- return -EINVAL; --} -- --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct rtrack2 *rt = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- ctrl->value = rt->muted; -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- if (rt->muted) -- ctrl->value = 0; -- else -- ctrl->value = 65535; -- return 0; -- } -- return -EINVAL; --} -- --static int vidioc_s_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct rtrack2 *rt = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (ctrl->value) -- rt_mute(rt); -- else -- rt_unmute(rt); -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- if (ctrl->value) -- rt_unmute(rt); -- else -- rt_mute(rt); -- return 0; -- } -- return -EINVAL; --} -- --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; -- return 0; --} -- --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) --{ -- return i ? -EINVAL : 0; --} -- --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; --} -- --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- return a->index ? -EINVAL : 0; --} -- --static const struct v4l2_file_operations rtrack2_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, -+static const struct radio_isa_ops rtrack2_ops = { -+ .alloc = rtrack2_alloc, -+ .s_mute_volume = rtrack2_s_mute_volume, -+ .s_frequency = rtrack2_s_frequency, -+ .g_signal = rtrack2_g_signal, - }; - --static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -+static const int rtrack2_ioports[] = { 0x20f, 0x30f }; -+ -+static struct radio_isa_driver rtrack2_driver = { -+ .driver = { -+ .match = radio_isa_match, -+ .probe = radio_isa_probe, -+ .remove = radio_isa_remove, -+ .driver = { -+ .name = "radio-rtrack2", -+ }, -+ }, -+ .io_params = io, -+ .radio_nr_params = radio_nr, -+ .io_ports = rtrack2_ioports, -+ .num_of_io_ports = ARRAY_SIZE(rtrack2_ioports), -+ .region_size = 4, -+ .card = "AIMSlab RadioTrack II", -+ .ops = &rtrack2_ops, -+ .has_stereo = true, - }; - - static int __init rtrack2_init(void) - { -- struct rtrack2 *dev = &rtrack2_card; -- struct v4l2_device *v4l2_dev = &dev->v4l2_dev; -- int res; -- -- strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name)); -- dev->io = io; -- if (dev->io == -1) { -- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n"); -- return -EINVAL; -- } -- if (!request_region(dev->io, 4, "rtrack2")) { -- v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io); -- return -EBUSY; -- } -- -- res = v4l2_device_register(NULL, v4l2_dev); -- if (res < 0) { -- release_region(dev->io, 4); -- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); -- return res; -- } -- -- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); -- dev->vdev.v4l2_dev = v4l2_dev; -- dev->vdev.fops = &rtrack2_fops; -- dev->vdev.ioctl_ops = &rtrack2_ioctl_ops; -- dev->vdev.release = video_device_release_empty; -- video_set_drvdata(&dev->vdev, dev); -- -- /* mute card - prevents noisy bootups */ -- outb(1, dev->io); -- dev->muted = 1; -- -- mutex_init(&dev->lock); -- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_device_unregister(v4l2_dev); -- release_region(dev->io, 4); -- return -EINVAL; -- } -- -- v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); -- -- return 0; -+ return isa_register_driver(&rtrack2_driver.driver, RTRACK2_MAX); - } - - static void __exit rtrack2_exit(void) - { -- struct rtrack2 *dev = &rtrack2_card; -- -- video_unregister_device(&dev->vdev); -- v4l2_device_unregister(&dev->v4l2_dev); -- release_region(dev->io, 4); -+ isa_unregister_driver(&rtrack2_driver.driver); - } - - module_init(rtrack2_init); -Index: linux-3.3.x86_64/drivers/media/radio/radio-terratec.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-terratec.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-terratec.c -@@ -16,11 +16,7 @@ - * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); - * Volume Control is done digitally - * -- * there is a I2C controlled RDS decoder (SAA6588) onboard, which i would like to support someday -- * (as soon i have understand how to get started :) -- * If you can help me out with that, please contact me!! -- * -- * -+ * Converted to the radio-isa framework by Hans Verkuil - * Converted to V4L2 API by Mauro Carvalho Chehab - */ - -@@ -30,43 +26,24 @@ - #include /* kernel radio structs */ - #include - #include /* outb, outb_p */ -+#include - #include - #include -+#include "radio-isa.h" - --MODULE_AUTHOR("R.OFFERMANNS & others"); -+MODULE_AUTHOR("R. Offermans & others"); - MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); - MODULE_LICENSE("GPL"); --MODULE_VERSION("0.0.3"); -- --#ifndef CONFIG_RADIO_TERRATEC_PORT --#define CONFIG_RADIO_TERRATEC_PORT 0x590 --#endif -+MODULE_VERSION("0.1.99"); - --static int io = CONFIG_RADIO_TERRATEC_PORT; -+/* Note: there seems to be only one possible port (0x590), but without -+ hardware this is hard to verify. For now, this is the only one we will -+ support. */ -+static int io = 0x590; - static int radio_nr = -1; - --module_param(io, int, 0); --MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); --module_param(radio_nr, int, 0); -- --static struct v4l2_queryctrl radio_qctrl[] = { -- { -- .id = V4L2_CID_AUDIO_MUTE, -- .name = "Mute", -- .minimum = 0, -- .maximum = 1, -- .default_value = 1, -- .type = V4L2_CTRL_TYPE_BOOLEAN, -- },{ -- .id = V4L2_CID_AUDIO_VOLUME, -- .name = "Volume", -- .minimum = 0, -- .maximum = 0xff, -- .step = 1, -- .default_value = 0xff, -- .type = V4L2_CTRL_TYPE_INTEGER, -- } --}; -+module_param(radio_nr, int, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device number"); - - #define WRT_DIS 0x00 - #define CLK_OFF 0x00 -@@ -76,63 +53,24 @@ static struct v4l2_queryctrl radio_qctrl - #define CLK_ON 0x08 - #define WRT_EN 0x10 - --struct terratec -+static struct radio_isa_card *terratec_alloc(void) - { -- struct v4l2_device v4l2_dev; -- struct video_device vdev; -- int io; -- int curvol; -- unsigned long curfreq; -- int muted; -- struct mutex lock; --}; -- --static struct terratec terratec_card; -- --/* local things */ -+ return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL); -+} - --static void tt_write_vol(struct terratec *tt, int volume) -+static int terratec_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) - { - int i; - -- volume = volume + (volume * 32); /* change both channels */ -- mutex_lock(&tt->lock); -+ if (mute) -+ vol = 0; -+ vol = vol + (vol * 32); /* change both channels */ - for (i = 0; i < 8; i++) { -- if (volume & (0x80 >> i)) -- outb(0x80, tt->io + 1); -+ if (vol & (0x80 >> i)) -+ outb(0x80, isa->io + 1); - else -- outb(0x00, tt->io + 1); -+ outb(0x00, isa->io + 1); - } -- mutex_unlock(&tt->lock); --} -- -- -- --static void tt_mute(struct terratec *tt) --{ -- tt->muted = 1; -- tt_write_vol(tt, 0); --} -- --static int tt_setvol(struct terratec *tt, int vol) --{ -- if (vol == tt->curvol) { /* requested volume = current */ -- if (tt->muted) { /* user is unmuting the card */ -- tt->muted = 0; -- tt_write_vol(tt, vol); /* enable card */ -- } -- return 0; -- } -- -- if (vol == 0) { /* volume = 0 means mute the card */ -- tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */ -- tt->curvol = vol; /* track the volume state! */ -- return 0; -- } -- -- tt->muted = 0; -- tt_write_vol(tt, vol); -- tt->curvol = vol; - return 0; - } - -@@ -140,20 +78,15 @@ static int tt_setvol(struct terratec *tt - /* this is the worst part in this driver */ - /* many more or less strange things are going on here, but hey, it works :) */ - --static int tt_setfreq(struct terratec *tt, unsigned long freq1) -+static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq) - { -- int freq; - int i; - int p; -- int temp; -+ int temp; - long rest; - unsigned char buffer[25]; /* we have to bit shift 25 registers */ - -- mutex_lock(&tt->lock); -- -- tt->curfreq = freq1; -- -- freq = freq1 / 160; /* convert the freq. to a nice to handle value */ -+ freq = freq / 160; /* convert the freq. to a nice to handle value */ - memset(buffer, 0, sizeof(buffer)); - - rest = freq * 10 + 10700; /* I once had understood what is going on here */ -@@ -175,239 +108,61 @@ static int tt_setfreq(struct terratec *t - - for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */ - if (buffer[i] == 1) { -- outb(WRT_EN | DATA, tt->io); -- outb(WRT_EN | DATA | CLK_ON, tt->io); -- outb(WRT_EN | DATA, tt->io); -+ outb(WRT_EN | DATA, isa->io); -+ outb(WRT_EN | DATA | CLK_ON, isa->io); -+ outb(WRT_EN | DATA, isa->io); - } else { -- outb(WRT_EN | 0x00, tt->io); -- outb(WRT_EN | 0x00 | CLK_ON, tt->io); -- } -- } -- outb(0x00, tt->io); -- -- mutex_unlock(&tt->lock); -- -- return 0; --} -- --static int tt_getsigstr(struct terratec *tt) --{ -- if (inb(tt->io) & 2) /* bit set = no signal present */ -- return 0; -- return 1; /* signal present */ --} -- --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); -- strlcpy(v->card, "ActiveRadio", sizeof(v->card)); -- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -- return 0; --} -- --static int vidioc_g_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- struct terratec *tt = video_drvdata(file); -- -- if (v->index > 0) -- return -EINVAL; -- -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- v->rangelow = 87 * 16000; -- v->rangehigh = 108 * 16000; -- v->rxsubchans = V4L2_TUNER_SUB_MONO; -- v->capability = V4L2_TUNER_CAP_LOW; -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->signal = 0xFFFF * tt_getsigstr(tt); -- return 0; --} -- --static int vidioc_s_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- return v->index ? -EINVAL : 0; --} -- --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct terratec *tt = video_drvdata(file); -- -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- tt_setfreq(tt, f->frequency); -- return 0; --} -- --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct terratec *tt = video_drvdata(file); -- -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = tt->curfreq; -- return 0; --} -- --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- int i; -- -- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { -- if (qc->id && qc->id == radio_qctrl[i].id) { -- memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); -- return 0; -+ outb(WRT_EN | 0x00, isa->io); -+ outb(WRT_EN | 0x00 | CLK_ON, isa->io); - } - } -- return -EINVAL; --} -- --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct terratec *tt = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (tt->muted) -- ctrl->value = 1; -- else -- ctrl->value = 0; -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- ctrl->value = tt->curvol * 6554; -- return 0; -- } -- return -EINVAL; --} -- --static int vidioc_s_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct terratec *tt = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (ctrl->value) -- tt_mute(tt); -- else -- tt_setvol(tt,tt->curvol); -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- tt_setvol(tt,ctrl->value); -- return 0; -- } -- return -EINVAL; --} -- --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; -+ outb(0x00, isa->io); - return 0; - } - --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -+static u32 terratec_g_signal(struct radio_isa_card *isa) - { -- return i ? -EINVAL : 0; -+ /* bit set = no signal present */ -+ return (inb(isa->io) & 2) ? 0 : 0xffff; - } - --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; --} -- --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- return a->index ? -EINVAL : 0; --} -- --static const struct v4l2_file_operations terratec_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, -+static const struct radio_isa_ops terratec_ops = { -+ .alloc = terratec_alloc, -+ .s_mute_volume = terratec_s_mute_volume, -+ .s_frequency = terratec_s_frequency, -+ .g_signal = terratec_g_signal, - }; - --static const struct v4l2_ioctl_ops terratec_ioctl_ops = { -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -+static const int terratec_ioports[] = { 0x590 }; -+ -+static struct radio_isa_driver terratec_driver = { -+ .driver = { -+ .match = radio_isa_match, -+ .probe = radio_isa_probe, -+ .remove = radio_isa_remove, -+ .driver = { -+ .name = "radio-terratec", -+ }, -+ }, -+ .io_params = &io, -+ .radio_nr_params = &radio_nr, -+ .io_ports = terratec_ioports, -+ .num_of_io_ports = ARRAY_SIZE(terratec_ioports), -+ .region_size = 2, -+ .card = "TerraTec ActiveRadio", -+ .ops = &terratec_ops, -+ .has_stereo = true, -+ .max_volume = 10, - }; - - static int __init terratec_init(void) - { -- struct terratec *tt = &terratec_card; -- struct v4l2_device *v4l2_dev = &tt->v4l2_dev; -- int res; -- -- strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name)); -- tt->io = io; -- if (tt->io == -1) { -- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n"); -- return -EINVAL; -- } -- if (!request_region(tt->io, 2, "terratec")) { -- v4l2_err(v4l2_dev, "port 0x%x already in use\n", io); -- return -EBUSY; -- } -- -- res = v4l2_device_register(NULL, v4l2_dev); -- if (res < 0) { -- release_region(tt->io, 2); -- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); -- return res; -- } -- -- strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name)); -- tt->vdev.v4l2_dev = v4l2_dev; -- tt->vdev.fops = &terratec_fops; -- tt->vdev.ioctl_ops = &terratec_ioctl_ops; -- tt->vdev.release = video_device_release_empty; -- video_set_drvdata(&tt->vdev, tt); -- -- mutex_init(&tt->lock); -- -- /* mute card - prevents noisy bootups */ -- tt_write_vol(tt, 0); -- -- if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_device_unregister(&tt->v4l2_dev); -- release_region(tt->io, 2); -- return -EINVAL; -- } -- -- v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); -- return 0; -+ return isa_register_driver(&terratec_driver.driver, 1); - } - - static void __exit terratec_exit(void) - { -- struct terratec *tt = &terratec_card; -- struct v4l2_device *v4l2_dev = &tt->v4l2_dev; -- -- video_unregister_device(&tt->vdev); -- v4l2_device_unregister(&tt->v4l2_dev); -- release_region(tt->io, 2); -- v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n"); -+ isa_unregister_driver(&terratec_driver.driver); - } - - module_init(terratec_init); -Index: linux-3.3.x86_64/drivers/media/radio/radio-trust.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-trust.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-trust.c -@@ -21,13 +21,15 @@ - #include - #include - #include -+#include - #include - #include -+#include "radio-isa.h" - - MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); - MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); - MODULE_LICENSE("GPL"); --MODULE_VERSION("0.0.3"); -+MODULE_VERSION("0.1.99"); - - /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ - -@@ -35,39 +37,38 @@ MODULE_VERSION("0.0.3"); - #define CONFIG_RADIO_TRUST_PORT -1 - #endif - --static int io = CONFIG_RADIO_TRUST_PORT; --static int radio_nr = -1; -+#define TRUST_MAX 2 - --module_param(io, int, 0); --MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); --module_param(radio_nr, int, 0); -+static int io[TRUST_MAX] = { [0] = CONFIG_RADIO_TRUST_PORT, -+ [1 ... (TRUST_MAX - 1)] = -1 }; -+static int radio_nr[TRUST_MAX] = { [0 ... (TRUST_MAX - 1)] = -1 }; -+ -+module_param_array(io, int, NULL, 0444); -+MODULE_PARM_DESC(io, "I/O addresses of the Trust FM Radio card (0x350 or 0x358)"); -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); - - struct trust { -- struct v4l2_device v4l2_dev; -- struct video_device vdev; -- int io; -+ struct radio_isa_card isa; - int ioval; -- __u16 curvol; -- __u16 curbass; -- __u16 curtreble; -- int muted; -- unsigned long curfreq; -- int curstereo; -- int curmute; -- struct mutex lock; - }; - --static struct trust trust_card; -+static struct radio_isa_card *trust_alloc(void) -+{ -+ struct trust *tr = kzalloc(sizeof(*tr), GFP_KERNEL); -+ -+ return tr ? &tr->isa : NULL; -+} - - /* i2c addresses */ - #define TDA7318_ADDR 0x88 - #define TSA6060T_ADDR 0xc4 - --#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0) --#define TR_SET_SCL outb(tr->ioval |= 2, tr->io) --#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io) --#define TR_SET_SDA outb(tr->ioval |= 1, tr->io) --#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io) -+#define TR_DELAY do { inb(tr->isa.io); inb(tr->isa.io); inb(tr->isa.io); } while (0) -+#define TR_SET_SCL outb(tr->ioval |= 2, tr->isa.io) -+#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->isa.io) -+#define TR_SET_SDA outb(tr->ioval |= 1, tr->isa.io) -+#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->isa.io) - - static void write_i2c(struct trust *tr, int n, ...) - { -@@ -84,10 +85,10 @@ static void write_i2c(struct trust *tr, - TR_CLR_SCL; - TR_DELAY; - -- for(; n; n--) { -+ for (; n; n--) { - val = va_arg(args, unsigned); -- for(mask = 0x80; mask; mask >>= 1) { -- if(val & mask) -+ for (mask = 0x80; mask; mask >>= 1) { -+ if (val & mask) - TR_SET_SDA; - else - TR_CLR_SDA; -@@ -115,317 +116,128 @@ static void write_i2c(struct trust *tr, - va_end(args); - } - --static void tr_setvol(struct trust *tr, __u16 vol) -+static int trust_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) - { -- mutex_lock(&tr->lock); -- tr->curvol = vol / 2048; -- write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f); -- mutex_unlock(&tr->lock); --} -+ struct trust *tr = container_of(isa, struct trust, isa); - --static int basstreble2chip[15] = { -- 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 --}; -- --static void tr_setbass(struct trust *tr, __u16 bass) --{ -- mutex_lock(&tr->lock); -- tr->curbass = bass / 4370; -- write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]); -- mutex_unlock(&tr->lock); -+ tr->ioval = (tr->ioval & 0xf7) | (mute << 3); -+ outb(tr->ioval, isa->io); -+ write_i2c(tr, 2, TDA7318_ADDR, vol ^ 0x1f); -+ return 0; - } - --static void tr_settreble(struct trust *tr, __u16 treble) -+static int trust_s_stereo(struct radio_isa_card *isa, bool stereo) - { -- mutex_lock(&tr->lock); -- tr->curtreble = treble / 4370; -- write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]); -- mutex_unlock(&tr->lock); --} -+ struct trust *tr = container_of(isa, struct trust, isa); - --static void tr_setstereo(struct trust *tr, int stereo) --{ -- mutex_lock(&tr->lock); -- tr->curstereo = !!stereo; -- tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2); -- outb(tr->ioval, tr->io); -- mutex_unlock(&tr->lock); --} -- --static void tr_setmute(struct trust *tr, int mute) --{ -- mutex_lock(&tr->lock); -- tr->curmute = !!mute; -- tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3); -- outb(tr->ioval, tr->io); -- mutex_unlock(&tr->lock); -+ tr->ioval = (tr->ioval & 0xfb) | (!stereo << 2); -+ outb(tr->ioval, isa->io); -+ return 0; - } - --static int tr_getsigstr(struct trust *tr) -+static u32 trust_g_signal(struct radio_isa_card *isa) - { - int i, v; - -- mutex_lock(&tr->lock); - for (i = 0, v = 0; i < 100; i++) -- v |= inb(tr->io); -- mutex_unlock(&tr->lock); -+ v |= inb(isa->io); - return (v & 1) ? 0 : 0xffff; - } - --static int tr_getstereo(struct trust *tr) --{ -- /* don't know how to determine it, just return the setting */ -- return tr->curstereo; --} -- --static void tr_setfreq(struct trust *tr, unsigned long f) --{ -- mutex_lock(&tr->lock); -- tr->curfreq = f; -- f /= 160; /* Convert to 10 kHz units */ -- f += 1070; /* Add 10.7 MHz IF */ -- write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); -- mutex_unlock(&tr->lock); --} -- --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- strlcpy(v->driver, "radio-trust", sizeof(v->driver)); -- strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); -- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -- return 0; --} -- --static int vidioc_g_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- struct trust *tr = video_drvdata(file); -- -- if (v->index > 0) -- return -EINVAL; -- -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- v->rangelow = 87.5 * 16000; -- v->rangehigh = 108 * 16000; -- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; -- v->capability = V4L2_TUNER_CAP_LOW; -- if (tr_getstereo(tr)) -- v->audmode = V4L2_TUNER_MODE_STEREO; -- else -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->signal = tr_getsigstr(tr); -- return 0; --} -- --static int vidioc_s_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) -+static int trust_s_frequency(struct radio_isa_card *isa, u32 freq) - { -- struct trust *tr = video_drvdata(file); -+ struct trust *tr = container_of(isa, struct trust, isa); - -- if (v->index) -- return -EINVAL; -- tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO); -+ freq /= 160; /* Convert to 10 kHz units */ -+ freq += 1070; /* Add 10.7 MHz IF */ -+ write_i2c(tr, 5, TSA6060T_ADDR, (freq << 1) | 1, -+ freq >> 7, 0x60 | ((freq >> 15) & 1), 0); - return 0; - } - --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct trust *tr = video_drvdata(file); -- -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- tr_setfreq(tr, f->frequency); -- return 0; --} -- --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct trust *tr = video_drvdata(file); -- -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = tr->curfreq; -- return 0; --} -- --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- switch (qc->id) { -- case V4L2_CID_AUDIO_MUTE: -- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); -- case V4L2_CID_AUDIO_VOLUME: -- return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535); -- case V4L2_CID_AUDIO_BASS: -- case V4L2_CID_AUDIO_TREBLE: -- return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768); -- } -- return -EINVAL; --} -- --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct trust *tr = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- ctrl->value = tr->curmute; -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- ctrl->value = tr->curvol * 2048; -- return 0; -- case V4L2_CID_AUDIO_BASS: -- ctrl->value = tr->curbass * 4370; -- return 0; -- case V4L2_CID_AUDIO_TREBLE: -- ctrl->value = tr->curtreble * 4370; -- return 0; -- } -- return -EINVAL; --} -+static int basstreble2chip[15] = { -+ 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 -+}; - --static int vidioc_s_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) -+static int trust_s_ctrl(struct v4l2_ctrl *ctrl) - { -- struct trust *tr = video_drvdata(file); -+ struct radio_isa_card *isa = -+ container_of(ctrl->handler, struct radio_isa_card, hdl); -+ struct trust *tr = container_of(isa, struct trust, isa); - - switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- tr_setmute(tr, ctrl->value); -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- tr_setvol(tr, ctrl->value); -- return 0; - case V4L2_CID_AUDIO_BASS: -- tr_setbass(tr, ctrl->value); -+ write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[ctrl->val]); - return 0; - case V4L2_CID_AUDIO_TREBLE: -- tr_settreble(tr, ctrl->value); -+ write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[ctrl->val]); - return 0; - } - return -EINVAL; - } - --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; -- return 0; --} -- --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) --{ -- return i ? -EINVAL : 0; --} -- --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; --} -- --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- return a->index ? -EINVAL : 0; --} -- --static const struct v4l2_file_operations trust_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, --}; -- --static const struct v4l2_ioctl_ops trust_ioctl_ops = { -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -+static const struct v4l2_ctrl_ops trust_ctrl_ops = { -+ .s_ctrl = trust_s_ctrl, - }; - --static int __init trust_init(void) -+static int trust_initialize(struct radio_isa_card *isa) - { -- struct trust *tr = &trust_card; -- struct v4l2_device *v4l2_dev = &tr->v4l2_dev; -- int res; -+ struct trust *tr = container_of(isa, struct trust, isa); - -- strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name)); -- tr->io = io; - tr->ioval = 0xf; -- mutex_init(&tr->lock); -- -- if (tr->io == -1) { -- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n"); -- return -EINVAL; -- } -- if (!request_region(tr->io, 2, "Trust FM Radio")) { -- v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io); -- return -EBUSY; -- } -- -- res = v4l2_device_register(NULL, v4l2_dev); -- if (res < 0) { -- release_region(tr->io, 2); -- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); -- return res; -- } -- -- strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name)); -- tr->vdev.v4l2_dev = v4l2_dev; -- tr->vdev.fops = &trust_fops; -- tr->vdev.ioctl_ops = &trust_ioctl_ops; -- tr->vdev.release = video_device_release_empty; -- video_set_drvdata(&tr->vdev, tr); -- - write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ - write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ - write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ - write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ - write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ - -- tr_setvol(tr, 0xffff); -- tr_setbass(tr, 0x8000); -- tr_settreble(tr, 0x8000); -- tr_setstereo(tr, 1); -- -- /* mute card - prevents noisy bootups */ -- tr_setmute(tr, 1); -- -- if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_device_unregister(v4l2_dev); -- release_region(tr->io, 2); -- return -EINVAL; -- } -+ v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops, -+ V4L2_CID_AUDIO_BASS, 0, 15, 1, 8); -+ v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops, -+ V4L2_CID_AUDIO_TREBLE, 0, 15, 1, 8); -+ return isa->hdl.error; -+} - -- v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); -+static const struct radio_isa_ops trust_ops = { -+ .init = trust_initialize, -+ .alloc = trust_alloc, -+ .s_mute_volume = trust_s_mute_volume, -+ .s_frequency = trust_s_frequency, -+ .s_stereo = trust_s_stereo, -+ .g_signal = trust_g_signal, -+}; - -- return 0; --} -+static const int trust_ioports[] = { 0x350, 0x358 }; -+ -+static struct radio_isa_driver trust_driver = { -+ .driver = { -+ .match = radio_isa_match, -+ .probe = radio_isa_probe, -+ .remove = radio_isa_remove, -+ .driver = { -+ .name = "radio-trust", -+ }, -+ }, -+ .io_params = io, -+ .radio_nr_params = radio_nr, -+ .io_ports = trust_ioports, -+ .num_of_io_ports = ARRAY_SIZE(trust_ioports), -+ .region_size = 2, -+ .card = "Trust FM Radio", -+ .ops = &trust_ops, -+ .has_stereo = true, -+ .max_volume = 31, -+}; - --static void __exit cleanup_trust_module(void) -+static int __init trust_init(void) - { -- struct trust *tr = &trust_card; -+ return isa_register_driver(&trust_driver.driver, TRUST_MAX); -+} - -- video_unregister_device(&tr->vdev); -- v4l2_device_unregister(&tr->v4l2_dev); -- release_region(tr->io, 2); -+static void __exit trust_exit(void) -+{ -+ isa_unregister_driver(&trust_driver.driver); - } - - module_init(trust_init); --module_exit(cleanup_trust_module); -+module_exit(trust_exit); -Index: linux-3.3.x86_64/drivers/media/radio/radio-typhoon.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-typhoon.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-typhoon.c -@@ -33,63 +33,53 @@ - #include /* request_region */ - #include /* kernel radio structs */ - #include /* outb, outb_p */ -+#include - #include - #include -+#include "radio-isa.h" - - #define DRIVER_VERSION "0.1.2" - - MODULE_AUTHOR("Dr. Henrik Seidel"); - MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); - MODULE_LICENSE("GPL"); --MODULE_VERSION(DRIVER_VERSION); -+MODULE_VERSION("0.1.99"); - - #ifndef CONFIG_RADIO_TYPHOON_PORT - #define CONFIG_RADIO_TYPHOON_PORT -1 - #endif - - #ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ --#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 -+#define CONFIG_RADIO_TYPHOON_MUTEFREQ 87000 - #endif - --static int io = CONFIG_RADIO_TYPHOON_PORT; --static int radio_nr = -1; -- --module_param(io, int, 0); --MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); -- --module_param(radio_nr, int, 0); -+#define TYPHOON_MAX 2 - -+static int io[TYPHOON_MAX] = { [0] = CONFIG_RADIO_TYPHOON_PORT, -+ [1 ... (TYPHOON_MAX - 1)] = -1 }; -+static int radio_nr[TYPHOON_MAX] = { [0 ... (TYPHOON_MAX - 1)] = -1 }; - static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ; -+ -+module_param_array(io, int, NULL, 0444); -+MODULE_PARM_DESC(io, "I/O addresses of the Typhoon card (0x316 or 0x336)"); -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); - module_param(mutefreq, ulong, 0); - MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); - --#define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n" -- - struct typhoon { -- struct v4l2_device v4l2_dev; -- struct video_device vdev; -- int io; -- int curvol; -+ struct radio_isa_card isa; - int muted; -- unsigned long curfreq; -- unsigned long mutefreq; -- struct mutex lock; - }; - --static struct typhoon typhoon_card; -- --static void typhoon_setvol_generic(struct typhoon *dev, int vol) -+static struct radio_isa_card *typhoon_alloc(void) - { -- mutex_lock(&dev->lock); -- vol >>= 14; /* Map 16 bit to 2 bit */ -- vol &= 3; -- outb_p(vol / 2, dev->io); /* Set the volume, high bit. */ -- outb_p(vol % 2, dev->io + 2); /* Set the volume, low bit. */ -- mutex_unlock(&dev->lock); -+ struct typhoon *ty = kzalloc(sizeof(*ty), GFP_KERNEL); -+ -+ return ty ? &ty->isa : NULL; - } - --static int typhoon_setfreq_generic(struct typhoon *dev, -- unsigned long frequency) -+static int typhoon_s_frequency(struct radio_isa_card *isa, u32 freq) - { - unsigned long outval; - unsigned long x; -@@ -105,302 +95,86 @@ static int typhoon_setfreq_generic(struc - * - */ - -- mutex_lock(&dev->lock); -- x = frequency / 160; -+ x = freq / 160; - outval = (x * x + 2500) / 5000; - outval = (outval * x + 5000) / 10000; - outval -= (10 * x * x + 10433) / 20866; - outval += 4 * x - 11505; - -- outb_p((outval >> 8) & 0x01, dev->io + 4); -- outb_p(outval >> 9, dev->io + 6); -- outb_p(outval & 0xff, dev->io + 8); -- mutex_unlock(&dev->lock); -- -- return 0; --} -- --static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency) --{ -- typhoon_setfreq_generic(dev, frequency); -- dev->curfreq = frequency; -- return 0; --} -- --static void typhoon_mute(struct typhoon *dev) --{ -- if (dev->muted == 1) -- return; -- typhoon_setvol_generic(dev, 0); -- typhoon_setfreq_generic(dev, dev->mutefreq); -- dev->muted = 1; --} -- --static void typhoon_unmute(struct typhoon *dev) --{ -- if (dev->muted == 0) -- return; -- typhoon_setfreq_generic(dev, dev->curfreq); -- typhoon_setvol_generic(dev, dev->curvol); -- dev->muted = 0; --} -- --static int typhoon_setvol(struct typhoon *dev, int vol) --{ -- if (dev->muted && vol != 0) { /* user is unmuting the card */ -- dev->curvol = vol; -- typhoon_unmute(dev); -- return 0; -- } -- if (vol == dev->curvol) /* requested volume == current */ -- return 0; -- -- if (vol == 0) { /* volume == 0 means mute the card */ -- typhoon_mute(dev); -- dev->curvol = vol; -- return 0; -- } -- typhoon_setvol_generic(dev, vol); -- dev->curvol = vol; -- return 0; --} -- --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); -- strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); -- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -- return 0; --} -- --static int vidioc_g_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- if (v->index > 0) -- return -EINVAL; -- -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- v->rangelow = 87.5 * 16000; -- v->rangehigh = 108 * 16000; -- v->rxsubchans = V4L2_TUNER_SUB_MONO; -- v->capability = V4L2_TUNER_CAP_LOW; -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->signal = 0xFFFF; /* We can't get the signal strength */ -+ outb_p((outval >> 8) & 0x01, isa->io + 4); -+ outb_p(outval >> 9, isa->io + 6); -+ outb_p(outval & 0xff, isa->io + 8); - return 0; - } - --static int vidioc_s_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- return v->index ? -EINVAL : 0; --} -- --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) -+static int typhoon_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) - { -- struct typhoon *dev = video_drvdata(file); -+ struct typhoon *ty = container_of(isa, struct typhoon, isa); - -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = dev->curfreq; -- return 0; --} -- --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct typhoon *dev = video_drvdata(file); -- -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- dev->curfreq = f->frequency; -- typhoon_setfreq(dev, dev->curfreq); -- return 0; --} -- --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- switch (qc->id) { -- case V4L2_CID_AUDIO_MUTE: -- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); -- case V4L2_CID_AUDIO_VOLUME: -- return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535); -- } -- return -EINVAL; --} -- --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct typhoon *dev = video_drvdata(file); -+ if (mute) -+ vol = 0; -+ vol >>= 14; /* Map 16 bit to 2 bit */ -+ vol &= 3; -+ outb_p(vol / 2, isa->io); /* Set the volume, high bit. */ -+ outb_p(vol % 2, isa->io + 2); /* Set the volume, low bit. */ - -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- ctrl->value = dev->muted; -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- ctrl->value = dev->curvol; -- return 0; -+ if (vol == 0 && !ty->muted) { -+ ty->muted = true; -+ return typhoon_s_frequency(isa, mutefreq << 4); - } -- return -EINVAL; --} -- --static int vidioc_s_ctrl (struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct typhoon *dev = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (ctrl->value) -- typhoon_mute(dev); -- else -- typhoon_unmute(dev); -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- typhoon_setvol(dev, ctrl->value); -- return 0; -+ if (vol && ty->muted) { -+ ty->muted = false; -+ return typhoon_s_frequency(isa, isa->freq); - } -- return -EINVAL; --} -- --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; - return 0; - } - --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) --{ -- return i ? -EINVAL : 0; --} -- --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; --} -- --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- return a->index ? -EINVAL : 0; --} -- --static int vidioc_log_status(struct file *file, void *priv) --{ -- struct typhoon *dev = video_drvdata(file); -- struct v4l2_device *v4l2_dev = &dev->v4l2_dev; -- -- v4l2_info(v4l2_dev, BANNER); --#ifdef MODULE -- v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n"); --#else -- v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n"); --#endif -- v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4); -- v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol); -- v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ? "on" : "off"); -- v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io); -- v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4); -- return 0; --} -- --static const struct v4l2_file_operations typhoon_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, -+static const struct radio_isa_ops typhoon_ops = { -+ .alloc = typhoon_alloc, -+ .s_mute_volume = typhoon_s_mute_volume, -+ .s_frequency = typhoon_s_frequency, - }; - --static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { -- .vidioc_log_status = vidioc_log_status, -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl, -+static const int typhoon_ioports[] = { 0x316, 0x336 }; -+ -+static struct radio_isa_driver typhoon_driver = { -+ .driver = { -+ .match = radio_isa_match, -+ .probe = radio_isa_probe, -+ .remove = radio_isa_remove, -+ .driver = { -+ .name = "radio-typhoon", -+ }, -+ }, -+ .io_params = io, -+ .radio_nr_params = radio_nr, -+ .io_ports = typhoon_ioports, -+ .num_of_io_ports = ARRAY_SIZE(typhoon_ioports), -+ .region_size = 8, -+ .card = "Typhoon Radio", -+ .ops = &typhoon_ops, -+ .has_stereo = true, -+ .max_volume = 3, - }; - - static int __init typhoon_init(void) - { -- struct typhoon *dev = &typhoon_card; -- struct v4l2_device *v4l2_dev = &dev->v4l2_dev; -- int res; -- -- strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); -- dev->io = io; -- -- if (dev->io == -1) { -- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); -- return -EINVAL; -- } -- -- if (mutefreq < 87000 || mutefreq > 108500) { -- v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); -- v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); -- return -EINVAL; -+ if (mutefreq < 87000 || mutefreq > 108000) { -+ printk(KERN_ERR "%s: You must set a frequency (in kHz) used when muting the card,\n", -+ typhoon_driver.driver.driver.name); -+ printk(KERN_ERR "%s: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108000)\n", -+ typhoon_driver.driver.driver.name); -+ return -ENODEV; - } -- dev->curfreq = dev->mutefreq = mutefreq << 4; -- -- mutex_init(&dev->lock); -- if (!request_region(dev->io, 8, "typhoon")) { -- v4l2_err(v4l2_dev, "port 0x%x already in use\n", -- dev->io); -- return -EBUSY; -- } -- -- res = v4l2_device_register(NULL, v4l2_dev); -- if (res < 0) { -- release_region(dev->io, 8); -- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); -- return res; -- } -- v4l2_info(v4l2_dev, BANNER); -- -- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); -- dev->vdev.v4l2_dev = v4l2_dev; -- dev->vdev.fops = &typhoon_fops; -- dev->vdev.ioctl_ops = &typhoon_ioctl_ops; -- dev->vdev.release = video_device_release_empty; -- video_set_drvdata(&dev->vdev, dev); -- -- /* mute card - prevents noisy bootups */ -- typhoon_mute(dev); -- -- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_device_unregister(&dev->v4l2_dev); -- release_region(dev->io, 8); -- return -EINVAL; -- } -- v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); -- v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq); -- -- return 0; -+ return isa_register_driver(&typhoon_driver.driver, TYPHOON_MAX); - } - - static void __exit typhoon_exit(void) - { -- struct typhoon *dev = &typhoon_card; -- -- video_unregister_device(&dev->vdev); -- v4l2_device_unregister(&dev->v4l2_dev); -- release_region(dev->io, 8); -+ isa_unregister_driver(&typhoon_driver.driver); - } - -+ - module_init(typhoon_init); - module_exit(typhoon_exit); - -Index: linux-3.3.x86_64/drivers/media/radio/radio-zoltrix.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-zoltrix.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-zoltrix.c -@@ -1,5 +1,6 @@ --/* zoltrix radio plus driver for Linux radio support -- * (c) 1998 C. van Schaik -+/* -+ * Zoltrix Radio Plus driver -+ * Copyright 1998 C. van Schaik - * - * BUGS - * Due to the inconsistency in reading from the signal flags -@@ -27,6 +28,14 @@ - * - * 2006-07-24 - Converted to V4L2 API - * by Mauro Carvalho Chehab -+ * -+ * Converted to the radio-isa framework by Hans Verkuil -+ * -+ * Note that this is the driver for the Zoltrix Radio Plus. -+ * This driver does not work for the Zoltrix Radio Plus 108 or the -+ * Zoltrix Radio Plus for Windows. -+ * -+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. - */ - - #include /* Modules */ -@@ -36,82 +45,70 @@ - #include /* kernel radio structs */ - #include - #include /* outb, outb_p */ -+#include - #include - #include -+#include "radio-isa.h" - --MODULE_AUTHOR("C.van Schaik"); -+MODULE_AUTHOR("C. van Schaik"); - MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); - MODULE_LICENSE("GPL"); --MODULE_VERSION("0.0.3"); -+MODULE_VERSION("0.1.99"); - - #ifndef CONFIG_RADIO_ZOLTRIX_PORT - #define CONFIG_RADIO_ZOLTRIX_PORT -1 - #endif - --static int io = CONFIG_RADIO_ZOLTRIX_PORT; --static int radio_nr = -1; -+#define ZOLTRIX_MAX 2 - --module_param(io, int, 0); --MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); --module_param(radio_nr, int, 0); -+static int io[ZOLTRIX_MAX] = { [0] = CONFIG_RADIO_ZOLTRIX_PORT, -+ [1 ... (ZOLTRIX_MAX - 1)] = -1 }; -+static int radio_nr[ZOLTRIX_MAX] = { [0 ... (ZOLTRIX_MAX - 1)] = -1 }; -+ -+module_param_array(io, int, NULL, 0444); -+MODULE_PARM_DESC(io, "I/O addresses of the Zoltrix Radio Plus card (0x20c or 0x30c)"); -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); - - struct zoltrix { -- struct v4l2_device v4l2_dev; -- struct video_device vdev; -- int io; -+ struct radio_isa_card isa; - int curvol; -- unsigned long curfreq; -- int muted; -- unsigned int stereo; -- struct mutex lock; -+ bool muted; - }; - --static struct zoltrix zoltrix_card; -+static struct radio_isa_card *zoltrix_alloc(void) -+{ -+ struct zoltrix *zol = kzalloc(sizeof(*zol), GFP_KERNEL); - --static int zol_setvol(struct zoltrix *zol, int vol) -+ return zol ? &zol->isa : NULL; -+} -+ -+static int zoltrix_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) - { -- zol->curvol = vol; -- if (zol->muted) -- return 0; -+ struct zoltrix *zol = container_of(isa, struct zoltrix, isa); - -- mutex_lock(&zol->lock); -- if (vol == 0) { -- outb(0, zol->io); -- outb(0, zol->io); -- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ -- mutex_unlock(&zol->lock); -+ zol->curvol = vol; -+ zol->muted = mute; -+ if (mute || vol == 0) { -+ outb(0, isa->io); -+ outb(0, isa->io); -+ inb(isa->io + 3); /* Zoltrix needs to be read to confirm */ - return 0; - } - -- outb(zol->curvol-1, zol->io); -+ outb(vol - 1, isa->io); - msleep(10); -- inb(zol->io + 2); -- mutex_unlock(&zol->lock); -+ inb(isa->io + 2); - return 0; - } - --static void zol_mute(struct zoltrix *zol) --{ -- zol->muted = 1; -- mutex_lock(&zol->lock); -- outb(0, zol->io); -- outb(0, zol->io); -- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ -- mutex_unlock(&zol->lock); --} -- --static void zol_unmute(struct zoltrix *zol) --{ -- zol->muted = 0; -- zol_setvol(zol, zol->curvol); --} -- --static int zol_setfreq(struct zoltrix *zol, unsigned long freq) -+/* tunes the radio to the desired frequency */ -+static int zoltrix_s_frequency(struct radio_isa_card *isa, u32 freq) - { -- /* tunes the radio to the desired frequency */ -- struct v4l2_device *v4l2_dev = &zol->v4l2_dev; -+ struct zoltrix *zol = container_of(isa, struct zoltrix, isa); -+ struct v4l2_device *v4l2_dev = &isa->v4l2_dev; - unsigned long long bitmask, f, m; -- unsigned int stereo = zol->stereo; -+ bool stereo = isa->stereo; - int i; - - if (freq == 0) { -@@ -125,340 +122,125 @@ static int zol_setfreq(struct zoltrix *z - bitmask = 0xc480402c10080000ull; - i = 45; - -- mutex_lock(&zol->lock); -- -- zol->curfreq = freq; -+ outb(0, isa->io); -+ outb(0, isa->io); -+ inb(isa->io + 3); /* Zoltrix needs to be read to confirm */ - -- outb(0, zol->io); -- outb(0, zol->io); -- inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ -- -- outb(0x40, zol->io); -- outb(0xc0, zol->io); -+ outb(0x40, isa->io); -+ outb(0xc0, isa->io); - - bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31)); - while (i--) { - if ((bitmask & 0x8000000000000000ull) != 0) { -- outb(0x80, zol->io); -+ outb(0x80, isa->io); - udelay(50); -- outb(0x00, zol->io); -+ outb(0x00, isa->io); - udelay(50); -- outb(0x80, zol->io); -+ outb(0x80, isa->io); - udelay(50); - } else { -- outb(0xc0, zol->io); -+ outb(0xc0, isa->io); - udelay(50); -- outb(0x40, zol->io); -+ outb(0x40, isa->io); - udelay(50); -- outb(0xc0, zol->io); -+ outb(0xc0, isa->io); - udelay(50); - } - bitmask *= 2; - } - /* termination sequence */ -- outb(0x80, zol->io); -- outb(0xc0, zol->io); -- outb(0x40, zol->io); -+ outb(0x80, isa->io); -+ outb(0xc0, isa->io); -+ outb(0x40, isa->io); - udelay(1000); -- inb(zol->io + 2); -- -+ inb(isa->io + 2); - udelay(1000); - -- if (zol->muted) { -- outb(0, zol->io); -- outb(0, zol->io); -- inb(zol->io + 3); -- udelay(1000); -- } -- -- mutex_unlock(&zol->lock); -- -- if (!zol->muted) -- zol_setvol(zol, zol->curvol); -- return 0; -+ return zoltrix_s_mute_volume(isa, zol->muted, zol->curvol); - } - - /* Get signal strength */ --static int zol_getsigstr(struct zoltrix *zol) -+static u32 zoltrix_g_rxsubchans(struct radio_isa_card *isa) - { -+ struct zoltrix *zol = container_of(isa, struct zoltrix, isa); - int a, b; - -- mutex_lock(&zol->lock); -- outb(0x00, zol->io); /* This stuff I found to do nothing */ -- outb(zol->curvol, zol->io); -+ outb(0x00, isa->io); /* This stuff I found to do nothing */ -+ outb(zol->curvol, isa->io); - msleep(20); - -- a = inb(zol->io); -+ a = inb(isa->io); - msleep(10); -- b = inb(zol->io); -- -- mutex_unlock(&zol->lock); -+ b = inb(isa->io); - -- if (a != b) -- return 0; -- -- /* I found this out by playing with a binary scanner on the card io */ -- return a == 0xcf || a == 0xdf || a == 0xef; -+ return (a == b && a == 0xcf) ? -+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - } - --static int zol_is_stereo(struct zoltrix *zol) -+static u32 zoltrix_g_signal(struct radio_isa_card *isa) - { -- int x1, x2; -- -- mutex_lock(&zol->lock); -+ struct zoltrix *zol = container_of(isa, struct zoltrix, isa); -+ int a, b; - -- outb(0x00, zol->io); -- outb(zol->curvol, zol->io); -+ outb(0x00, isa->io); /* This stuff I found to do nothing */ -+ outb(zol->curvol, isa->io); - msleep(20); - -- x1 = inb(zol->io); -+ a = inb(isa->io); - msleep(10); -- x2 = inb(zol->io); -- -- mutex_unlock(&zol->lock); -- -- return x1 == x2 && x1 == 0xcf; --} -- --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); -- strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); -- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -- return 0; --} -- --static int vidioc_g_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- struct zoltrix *zol = video_drvdata(file); -- -- if (v->index > 0) -- return -EINVAL; -- -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- v->rangelow = 88 * 16000; -- v->rangehigh = 108 * 16000; -- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; -- v->capability = V4L2_TUNER_CAP_LOW; -- if (zol_is_stereo(zol)) -- v->audmode = V4L2_TUNER_MODE_STEREO; -- else -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->signal = 0xFFFF * zol_getsigstr(zol); -- return 0; --} -- --static int vidioc_s_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- return v->index ? -EINVAL : 0; --} -- --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct zoltrix *zol = video_drvdata(file); -- -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- if (zol_setfreq(zol, f->frequency) != 0) -- return -EINVAL; -- return 0; --} -- --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct zoltrix *zol = video_drvdata(file); -- -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = zol->curfreq; -- return 0; --} -- --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- switch (qc->id) { -- case V4L2_CID_AUDIO_MUTE: -- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); -- case V4L2_CID_AUDIO_VOLUME: -- return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535); -- } -- return -EINVAL; --} -- --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct zoltrix *zol = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- ctrl->value = zol->muted; -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- ctrl->value = zol->curvol * 4096; -- return 0; -- } -- return -EINVAL; --} -+ b = inb(isa->io); - --static int vidioc_s_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) --{ -- struct zoltrix *zol = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- if (ctrl->value) -- zol_mute(zol); -- else { -- zol_unmute(zol); -- zol_setvol(zol, zol->curvol); -- } -- return 0; -- case V4L2_CID_AUDIO_VOLUME: -- zol_setvol(zol, ctrl->value / 4096); -+ if (a != b) - return 0; -- } -- zol->stereo = 1; -- if (zol_setfreq(zol, zol->curfreq) != 0) -- return -EINVAL; --#if 0 --/* FIXME: Implement stereo/mono switch on V4L2 */ -- if (v->mode & VIDEO_SOUND_STEREO) { -- zol->stereo = 1; -- zol_setfreq(zol, zol->curfreq); -- } -- if (v->mode & VIDEO_SOUND_MONO) { -- zol->stereo = 0; -- zol_setfreq(zol, zol->curfreq); -- } --#endif -- return -EINVAL; --} -- --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; -- return 0; --} -- --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) --{ -- return i ? -EINVAL : 0; --} - --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; -+ /* I found this out by playing with a binary scanner on the card io */ -+ return (a == 0xcf || a == 0xdf || a == 0xef) ? 0xffff : 0; - } - --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) -+static int zoltrix_s_stereo(struct radio_isa_card *isa, bool stereo) - { -- return a->index ? -EINVAL : 0; -+ return zoltrix_s_frequency(isa, isa->freq); - } - --static const struct v4l2_file_operations zoltrix_fops = --{ -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, -+static const struct radio_isa_ops zoltrix_ops = { -+ .alloc = zoltrix_alloc, -+ .s_mute_volume = zoltrix_s_mute_volume, -+ .s_frequency = zoltrix_s_frequency, -+ .s_stereo = zoltrix_s_stereo, -+ .g_rxsubchans = zoltrix_g_rxsubchans, -+ .g_signal = zoltrix_g_signal, - }; - --static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl, -+static const int zoltrix_ioports[] = { 0x20c, 0x30c }; -+ -+static struct radio_isa_driver zoltrix_driver = { -+ .driver = { -+ .match = radio_isa_match, -+ .probe = radio_isa_probe, -+ .remove = radio_isa_remove, -+ .driver = { -+ .name = "radio-zoltrix", -+ }, -+ }, -+ .io_params = io, -+ .radio_nr_params = radio_nr, -+ .io_ports = zoltrix_ioports, -+ .num_of_io_ports = ARRAY_SIZE(zoltrix_ioports), -+ .region_size = 2, -+ .card = "Zoltrix Radio Plus", -+ .ops = &zoltrix_ops, -+ .has_stereo = true, -+ .max_volume = 15, - }; - - static int __init zoltrix_init(void) - { -- struct zoltrix *zol = &zoltrix_card; -- struct v4l2_device *v4l2_dev = &zol->v4l2_dev; -- int res; -- -- strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name)); -- zol->io = io; -- if (zol->io == -1) { -- v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n"); -- return -EINVAL; -- } -- if (zol->io != 0x20c && zol->io != 0x30c) { -- v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n"); -- return -ENXIO; -- } -- -- if (!request_region(zol->io, 2, "zoltrix")) { -- v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io); -- return -EBUSY; -- } -- -- res = v4l2_device_register(NULL, v4l2_dev); -- if (res < 0) { -- release_region(zol->io, 2); -- v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); -- return res; -- } -- -- mutex_init(&zol->lock); -- -- /* mute card - prevents noisy bootups */ -- -- /* this ensures that the volume is all the way down */ -- -- outb(0, zol->io); -- outb(0, zol->io); -- msleep(20); -- inb(zol->io + 3); -- -- zol->curvol = 0; -- zol->stereo = 1; -- -- strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); -- zol->vdev.v4l2_dev = v4l2_dev; -- zol->vdev.fops = &zoltrix_fops; -- zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; -- zol->vdev.release = video_device_release_empty; -- video_set_drvdata(&zol->vdev, zol); -- -- if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_device_unregister(v4l2_dev); -- release_region(zol->io, 2); -- return -EINVAL; -- } -- v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); -- -- return 0; -+ return isa_register_driver(&zoltrix_driver.driver, ZOLTRIX_MAX); - } - - static void __exit zoltrix_exit(void) - { -- struct zoltrix *zol = &zoltrix_card; -- -- video_unregister_device(&zol->vdev); -- v4l2_device_unregister(&zol->v4l2_dev); -- release_region(zol->io, 2); -+ isa_unregister_driver(&zoltrix_driver.driver); - } - - module_init(zoltrix_init); -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-core/dvb_frontend.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-core/dvb_frontend.c -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-core/dvb_frontend.c -@@ -148,7 +148,7 @@ static int dtv_property_legacy_params_sy - - static bool has_get_frontend(struct dvb_frontend *fe) - { -- return fe->ops.get_frontend; -+ return fe->ops.get_frontend != NULL; - } - - /* -Index: linux-3.3.x86_64/drivers/media/common/tuners/xc5000.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/common/tuners/xc5000.c -+++ linux-3.3.x86_64/drivers/media/common/tuners/xc5000.c -@@ -49,9 +49,6 @@ static LIST_HEAD(hybrid_tuner_instance_l - #define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) - --#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" --#define XC5000_DEFAULT_FIRMWARE_SIZE 12401 -- - struct xc5000_priv { - struct tuner_i2c_props i2c_props; - struct list_head hybrid_tuner_instance_list; -@@ -62,6 +59,8 @@ struct xc5000_priv { - u8 video_standard; - u8 rf_mode; - u8 radio_input; -+ -+ int chip_id; - }; - - /* Misc Defines */ -@@ -204,6 +203,33 @@ static struct XC_TV_STANDARD XC5000_Stan - {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} - }; - -+ -+struct xc5000_fw_cfg { -+ char *name; -+ u16 size; -+}; -+ -+static const struct xc5000_fw_cfg xc5000a_1_6_114 = { -+ .name = "dvb-fe-xc5000-1.6.114.fw", -+ .size = 12401, -+}; -+ -+static const struct xc5000_fw_cfg xc5000c_41_024_5_31875 = { -+ .name = "dvb-fe-xc5000c-41.024.5-31875.fw", -+ .size = 16503, -+}; -+ -+static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) -+{ -+ switch (chip_id) { -+ default: -+ case XC5000A: -+ return &xc5000a_1_6_114; -+ case XC5000C: -+ return &xc5000c_41_024_5_31875; -+ } -+} -+ - static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); - static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); - static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); -@@ -552,12 +578,14 @@ static int xc5000_fwupload(struct dvb_fr - struct xc5000_priv *priv = fe->tuner_priv; - const struct firmware *fw; - int ret; -+ const struct xc5000_fw_cfg *desired_fw = -+ xc5000_assign_firmware(priv->chip_id); - - /* request the firmware, this will block and timeout */ - printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", -- XC5000_DEFAULT_FIRMWARE); -+ desired_fw->name); - -- ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, -+ ret = request_firmware(&fw, desired_fw->name, - priv->i2c_props.adap->dev.parent); - if (ret) { - printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); -@@ -569,7 +597,7 @@ static int xc5000_fwupload(struct dvb_fr - ret = XC_RESULT_SUCCESS; - } - -- if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { -+ if (fw->size != desired_fw->size) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); - ret = XC_RESULT_RESET_FAILURE; - } else { -@@ -1139,6 +1167,13 @@ struct dvb_frontend *xc5000_attach(struc - if (priv->radio_input == 0) - priv->radio_input = cfg->radio_input; - -+ /* don't override chip id if it's already been set -+ unless explicitly specified */ -+ if ((priv->chip_id == 0) || (cfg->chip_id)) -+ /* use default chip id if none specified, set to 0 so -+ it can be overridden if this is a hybrid driver */ -+ priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; -+ - /* Check if firmware has been loaded. It is possible that another - instance of the driver has loaded the firmware. - */ -Index: linux-3.3.x86_64/drivers/media/common/tuners/xc5000.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/common/tuners/xc5000.h -+++ linux-3.3.x86_64/drivers/media/common/tuners/xc5000.h -@@ -27,10 +27,15 @@ - struct dvb_frontend; - struct i2c_adapter; - -+#define XC5000A 1 -+#define XC5000C 2 -+ - struct xc5000_config { - u8 i2c_address; - u32 if_khz; - u8 radio_input; -+ -+ int chip_id; - }; - - /* xc5000 callback command */ -Index: linux-3.3.x86_64/drivers/media/common/tuners/tuner-types.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/common/tuners/tuner-types.c -+++ linux-3.3.x86_64/drivers/media/common/tuners/tuner-types.c -@@ -1868,6 +1868,10 @@ struct tunertype tuners[] = { - .params = tuner_tena_tnf_5337_params, - .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), - }, -+ [TUNER_XC5000C] = { /* Xceive 5000C */ -+ .name = "Xceive 5000C tuner", -+ /* see xc5000.c for details */ -+ }, - }; - EXPORT_SYMBOL(tuners); - -Index: linux-3.3.x86_64/drivers/media/video/tuner-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tuner-core.c -+++ linux-3.3.x86_64/drivers/media/video/tuner-core.c -@@ -380,6 +380,21 @@ static void set_type(struct i2c_client * - tune_now = 0; - break; - } -+ case TUNER_XC5000C: -+ { -+ struct xc5000_config xc5000c_cfg = { -+ .i2c_address = t->i2c->addr, -+ /* if_khz will be set at dvb_attach() */ -+ .if_khz = 0, -+ .chip_id = XC5000C, -+ }; -+ -+ if (!dvb_attach(xc5000_attach, -+ &t->fe, t->i2c->adapter, &xc5000c_cfg)) -+ goto attach_failed; -+ tune_now = 0; -+ break; -+ } - case TUNER_NXP_TDA18271: - { - struct tda18271_config cfg = { -@@ -1314,18 +1329,7 @@ static struct i2c_driver tuner_driver = - .id_table = tuner_id, - }; - --static __init int init_tuner(void) --{ -- return i2c_add_driver(&tuner_driver); --} -- --static __exit void exit_tuner(void) --{ -- i2c_del_driver(&tuner_driver); --} -- --module_init(init_tuner); --module_exit(exit_tuner); -+module_i2c_driver(tuner_driver); - - MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); - MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -Index: linux-3.3.x86_64/include/media/tuner.h -=================================================================== ---- linux-3.3.x86_64.orig/include/media/tuner.h -+++ linux-3.3.x86_64/include/media/tuner.h -@@ -136,6 +136,7 @@ - #define TUNER_TENA_TNF_5337 86 - - #define TUNER_XC4000 87 /* Xceive Silicon Tuner */ -+#define TUNER_XC5000C 88 /* Xceive Silicon Tuner */ - - /* tv card specific */ - #define TDA9887_PRESENT (1<<0) -Index: linux-3.3.x86_64/drivers/media/video/tveeprom.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tveeprom.c -+++ linux-3.3.x86_64/drivers/media/video/tveeprom.c -@@ -286,8 +286,16 @@ hauppauge_tuner[] = - { TUNER_ABSENT, "MaxLinear 301"}, - { TUNER_ABSENT, "Mirics MSi001"}, - { TUNER_ABSENT, "MaxLinear MxL241SF"}, -- { TUNER_ABSENT, "Xceive XC5000C"}, -+ { TUNER_XC5000C, "Xceive XC5000C"}, - { TUNER_ABSENT, "Montage M68TS2020"}, -+ { TUNER_ABSENT, "Siano SMS1530"}, -+ { TUNER_ABSENT, "Dibcom 7090"}, -+ { TUNER_ABSENT, "Xceive XC5200C"}, -+ { TUNER_ABSENT, "NXP 18273"}, -+ { TUNER_ABSENT, "Montage M88TS2022"}, -+ /* 180-189 */ -+ { TUNER_ABSENT, "NXP 18272M"}, -+ { TUNER_ABSENT, "NXP 18272S"}, - }; - - /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are -Index: linux-3.3.x86_64/drivers/media/radio/radio-sf16fmr2.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-sf16fmr2.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-sf16fmr2.c -@@ -9,16 +9,23 @@ - #include - #include /* Modules */ - #include /* Initdata */ -+#include - #include /* request_region */ - #include /* outb, outb_p */ -+#include - #include - - MODULE_AUTHOR("Ondrej Zary"); - MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); - MODULE_LICENSE("GPL"); - -+static int radio_nr = -1; -+module_param(radio_nr, int, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device number"); -+ - struct fmr2 { - int io; -+ struct v4l2_device v4l2_dev; - struct snd_tea575x tea; - struct v4l2_ctrl *volume; - struct v4l2_ctrl *balance; -@@ -26,7 +33,6 @@ struct fmr2 { - - /* the port is hardwired so no need to support multiple cards */ - #define FMR2_PORT 0x384 --static struct fmr2 fmr2_card; - - /* TEA575x tuner pins */ - #define STR_DATA (1 << 0) -@@ -172,7 +178,7 @@ static int fmr2_tea_ext_init(struct snd_ - fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56); - fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0); - if (tea->ctrl_handler.error) { -- printk(KERN_ERR "radio-sf16fmr2: can't initialize contrls\n"); -+ printk(KERN_ERR "radio-sf16fmr2: can't initialize controls\n"); - return tea->ctrl_handler.error; - } - } -@@ -180,26 +186,46 @@ static int fmr2_tea_ext_init(struct snd_ - return 0; - } - --static int __init fmr2_init(void) -+static int __devinit fmr2_probe(struct device *pdev, unsigned int dev) - { -- struct fmr2 *fmr2 = &fmr2_card; -+ struct fmr2 *fmr2; -+ int err; -+ -+ fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL); -+ if (fmr2 == NULL) -+ return -ENOMEM; - -+ strlcpy(fmr2->v4l2_dev.name, dev_name(pdev), -+ sizeof(fmr2->v4l2_dev.name)); - fmr2->io = FMR2_PORT; - -- if (!request_region(fmr2->io, 2, "SF16-FMR2")) { -+ if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) { - printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); -+ kfree(fmr2); - return -EBUSY; - } - -+ dev_set_drvdata(pdev, fmr2); -+ err = v4l2_device_register(pdev, &fmr2->v4l2_dev); -+ if (err < 0) { -+ v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n"); -+ release_region(fmr2->io, 2); -+ kfree(fmr2); -+ return err; -+ } -+ fmr2->tea.v4l2_dev = &fmr2->v4l2_dev; - fmr2->tea.private_data = fmr2; -+ fmr2->tea.radio_nr = radio_nr; - fmr2->tea.ops = &fmr2_tea_ops; - fmr2->tea.ext_init = fmr2_tea_ext_init; - strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); -- strcpy(fmr2->tea.bus_info, "ISA"); -+ snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s", -+ fmr2->v4l2_dev.name); - - if (snd_tea575x_init(&fmr2->tea)) { - printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); - release_region(fmr2->io, 2); -+ kfree(fmr2); - return -ENODEV; - } - -@@ -207,12 +233,33 @@ static int __init fmr2_init(void) - return 0; - } - --static void __exit fmr2_exit(void) -+static int __exit fmr2_remove(struct device *pdev, unsigned int dev) - { -- struct fmr2 *fmr2 = &fmr2_card; -+ struct fmr2 *fmr2 = dev_get_drvdata(pdev); - - snd_tea575x_exit(&fmr2->tea); - release_region(fmr2->io, 2); -+ v4l2_device_unregister(&fmr2->v4l2_dev); -+ kfree(fmr2); -+ return 0; -+} -+ -+struct isa_driver fmr2_driver = { -+ .probe = fmr2_probe, -+ .remove = fmr2_remove, -+ .driver = { -+ .name = "radio-sf16fmr2", -+ }, -+}; -+ -+static int __init fmr2_init(void) -+{ -+ return isa_register_driver(&fmr2_driver, 1); -+} -+ -+static void __exit fmr2_exit(void) -+{ -+ isa_unregister_driver(&fmr2_driver); - } - - module_init(fmr2_init); -Index: linux-3.3.x86_64/drivers/media/video/davinci/dm355_ccdc.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/davinci/dm355_ccdc.c -+++ linux-3.3.x86_64/drivers/media/video/davinci/dm355_ccdc.c -@@ -292,7 +292,7 @@ static int validate_ccdc_param(struct cc - if ((ccdcparam->med_filt_thres < 0) || - (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { - dev_dbg(ccdc_cfg.dev, -- "Invalid value of median filter thresold\n"); -+ "Invalid value of median filter threshold\n"); - return -EINVAL; - } - -Index: linux-3.3.x86_64/drivers/media/video/Kconfig -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/Kconfig -+++ linux-3.3.x86_64/drivers/media/video/Kconfig -@@ -273,6 +273,16 @@ config VIDEO_ADV7180 - To compile this driver as a module, choose M here: the - module will be called adv7180. - -+config VIDEO_ADV7183 -+ tristate "Analog Devices ADV7183 decoder" -+ depends on VIDEO_V4L2 && I2C -+ ---help--- -+ V4l2 subdevice driver for the Analog Devices -+ ADV7183 video decoder. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called adv7183. -+ - config VIDEO_BT819 - tristate "BT819A VideoStream decoder" - depends on VIDEO_V4L2 && I2C -@@ -459,6 +469,9 @@ config VIDEO_AK881X - - comment "Camera sensor devices" - -+config VIDEO_APTINA_PLL -+ tristate -+ - config VIDEO_OV7670 - tristate "OmniVision OV7670 sensor support" - depends on I2C && VIDEO_V4L2 -@@ -467,9 +480,28 @@ config VIDEO_OV7670 - OV7670 VGA camera. It currently only works with the M88ALP01 - controller. - -+config VIDEO_VS6624 -+ tristate "ST VS6624 sensor support" -+ depends on VIDEO_V4L2 && I2C -+ ---help--- -+ This is a Video4Linux2 sensor-level driver for the ST VS6624 -+ camera. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called vs6624. -+ -+config VIDEO_MT9M032 -+ tristate "MT9M032 camera sensor support" -+ depends on I2C && VIDEO_V4L2 -+ select VIDEO_APTINA_PLL -+ ---help--- -+ This driver supports MT9M032 camera sensors from Aptina, monochrome -+ models only. -+ - config VIDEO_MT9P031 - tristate "Aptina MT9P031 support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API -+ select VIDEO_APTINA_PLL - ---help--- - This is a Video4Linux2 sensor-level driver for the Aptina - (Micron) mt9p031 5 Mpixel camera. -@@ -851,6 +883,8 @@ source "drivers/media/video/davinci/Kcon - - source "drivers/media/video/omap/Kconfig" - -+source "drivers/media/video/blackfin/Kconfig" -+ - config VIDEO_SH_VOU - tristate "SuperH VOU video output driver" - depends on VIDEO_DEV && ARCH_SHMOBILE -@@ -1087,7 +1121,7 @@ config VIDEO_MX2_HOSTSUPPORT - config VIDEO_MX2 - tristate "i.MX27/i.MX25 Camera Sensor Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25) -- select VIDEOBUF_DMA_CONTIG -+ select VIDEOBUF2_DMA_CONTIG - select VIDEO_MX2_HOSTSUPPORT - ---help--- - This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor -@@ -1116,7 +1150,8 @@ config VIDEO_ATMEL_ISI - - config VIDEO_S5P_MIPI_CSIS - tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" -- depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API -+ depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P -+ depends on VIDEO_V4L2_SUBDEV_API && REGULATOR - ---help--- - This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. - -@@ -1176,4 +1211,14 @@ config VIDEO_SAMSUNG_S5P_MFC - help - MFC 5.1 driver for V4L2. - -+config VIDEO_MX2_EMMAPRP -+ tristate "MX2 eMMa-PrP support" -+ depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27 -+ select VIDEOBUF2_DMA_CONTIG -+ select V4L2_MEM2MEM_DEV -+ help -+ MX2X chips have a PrP that can be used to process buffers from -+ memory to memory. Operations include resizing and format -+ conversion. -+ - endif # V4L_MEM2MEM_DRIVERS -Index: linux-3.3.x86_64/drivers/media/video/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/Makefile -+++ linux-3.3.x86_64/drivers/media/video/Makefile -@@ -12,16 +12,19 @@ omap2cam-objs := omap24xxcam.o omap24xxc - - videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ - v4l2-event.o v4l2-ctrls.o v4l2-subdev.o -+ifeq ($(CONFIG_COMPAT),y) -+ videodev-objs += v4l2-compat-ioctl32.o -+endif - - # V4L2 core modules - - obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o --ifeq ($(CONFIG_COMPAT),y) -- obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o --endif -- - obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o - -+# Helper modules -+ -+obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o -+ - # All i2c modules must come first: - - obj-$(CONFIG_VIDEO_TUNER) += tuner.o -@@ -40,8 +43,10 @@ obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o - obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o - obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o - obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o -+obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o - obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o - obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o -+obj-$(CONFIG_VIDEO_VS6624) += vs6624.o - obj-$(CONFIG_VIDEO_BT819) += bt819.o - obj-$(CONFIG_VIDEO_BT856) += bt856.o - obj-$(CONFIG_VIDEO_BT866) += bt866.o -@@ -65,6 +70,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083 - obj-$(CONFIG_VIDEO_OV7670) += ov7670.o - obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o - obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o -+obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o - obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o - obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o - obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o -@@ -177,6 +183,8 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_ - obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o - obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o - -+obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o -+ - obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ - obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ - obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ -@@ -184,6 +192,8 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5 - - obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ - -+obj-$(CONFIG_BLACKFIN) += blackfin/ -+ - obj-$(CONFIG_ARCH_DAVINCI) += davinci/ - - obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o -@@ -199,6 +209,6 @@ obj-y += davinci/ - - obj-$(CONFIG_ARCH_OMAP) += omap/ - --ccflags-y += -Idrivers/media/dvb/dvb-core --ccflags-y += -Idrivers/media/dvb/frontends --ccflags-y += -Idrivers/media/common/tuners -+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core -+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends -+ccflags-y += -I$(srctree)/drivers/media/common/tuners -Index: linux-3.3.x86_64/drivers/media/video/mx2_emmaprp.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/mx2_emmaprp.c -@@ -0,0 +1,1008 @@ -+/* -+ * Support eMMa-PrP through mem2mem framework. -+ * -+ * eMMa-PrP is a piece of HW that allows fetching buffers -+ * from one memory location and do several operations on -+ * them such as scaling or format conversion giving, as a result -+ * a new processed buffer in another memory location. -+ * -+ * Based on mem2mem_testdev.c by Pawel Osciak. -+ * -+ * Copyright (c) 2011 Vista Silicon S.L. -+ * Javier Martin -+ * -+ * 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 -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define EMMAPRP_MODULE_NAME "mem2mem-emmaprp" -+ -+MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs"); -+MODULE_AUTHOR("Javier Martin v4l2_dev, "%s: " fmt, __func__, ## arg) -+ -+/* EMMA PrP */ -+#define PRP_CNTL 0x00 -+#define PRP_INTR_CNTL 0x04 -+#define PRP_INTRSTATUS 0x08 -+#define PRP_SOURCE_Y_PTR 0x0c -+#define PRP_SOURCE_CB_PTR 0x10 -+#define PRP_SOURCE_CR_PTR 0x14 -+#define PRP_DEST_RGB1_PTR 0x18 -+#define PRP_DEST_RGB2_PTR 0x1c -+#define PRP_DEST_Y_PTR 0x20 -+#define PRP_DEST_CB_PTR 0x24 -+#define PRP_DEST_CR_PTR 0x28 -+#define PRP_SRC_FRAME_SIZE 0x2c -+#define PRP_DEST_CH1_LINE_STRIDE 0x30 -+#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 -+#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 -+#define PRP_CH1_OUT_IMAGE_SIZE 0x3c -+#define PRP_CH2_OUT_IMAGE_SIZE 0x40 -+#define PRP_SRC_LINE_STRIDE 0x44 -+#define PRP_CSC_COEF_012 0x48 -+#define PRP_CSC_COEF_345 0x4c -+#define PRP_CSC_COEF_678 0x50 -+#define PRP_CH1_RZ_HORI_COEF1 0x54 -+#define PRP_CH1_RZ_HORI_COEF2 0x58 -+#define PRP_CH1_RZ_HORI_VALID 0x5c -+#define PRP_CH1_RZ_VERT_COEF1 0x60 -+#define PRP_CH1_RZ_VERT_COEF2 0x64 -+#define PRP_CH1_RZ_VERT_VALID 0x68 -+#define PRP_CH2_RZ_HORI_COEF1 0x6c -+#define PRP_CH2_RZ_HORI_COEF2 0x70 -+#define PRP_CH2_RZ_HORI_VALID 0x74 -+#define PRP_CH2_RZ_VERT_COEF1 0x78 -+#define PRP_CH2_RZ_VERT_COEF2 0x7c -+#define PRP_CH2_RZ_VERT_VALID 0x80 -+ -+#define PRP_CNTL_CH1EN (1 << 0) -+#define PRP_CNTL_CH2EN (1 << 1) -+#define PRP_CNTL_CSIEN (1 << 2) -+#define PRP_CNTL_DATA_IN_YUV420 (0 << 3) -+#define PRP_CNTL_DATA_IN_YUV422 (1 << 3) -+#define PRP_CNTL_DATA_IN_RGB16 (2 << 3) -+#define PRP_CNTL_DATA_IN_RGB32 (3 << 3) -+#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) -+#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) -+#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) -+#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) -+#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) -+#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) -+#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) -+#define PRP_CNTL_CH1_LEN (1 << 9) -+#define PRP_CNTL_CH2_LEN (1 << 10) -+#define PRP_CNTL_SKIP_FRAME (1 << 11) -+#define PRP_CNTL_SWRST (1 << 12) -+#define PRP_CNTL_CLKEN (1 << 13) -+#define PRP_CNTL_WEN (1 << 14) -+#define PRP_CNTL_CH1BYP (1 << 15) -+#define PRP_CNTL_IN_TSKIP(x) ((x) << 16) -+#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) -+#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) -+#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) -+#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) -+#define PRP_CNTL_CH2B1EN (1 << 29) -+#define PRP_CNTL_CH2B2EN (1 << 30) -+#define PRP_CNTL_CH2FEN (1 << 31) -+ -+#define PRP_SIZE_HEIGHT(x) (x) -+#define PRP_SIZE_WIDTH(x) ((x) << 16) -+ -+/* IRQ Enable and status register */ -+#define PRP_INTR_RDERR (1 << 0) -+#define PRP_INTR_CH1WERR (1 << 1) -+#define PRP_INTR_CH2WERR (1 << 2) -+#define PRP_INTR_CH1FC (1 << 3) -+#define PRP_INTR_CH2FC (1 << 5) -+#define PRP_INTR_LBOVF (1 << 7) -+#define PRP_INTR_CH2OVF (1 << 8) -+ -+#define PRP_INTR_ST_RDERR (1 << 0) -+#define PRP_INTR_ST_CH1WERR (1 << 1) -+#define PRP_INTR_ST_CH2WERR (1 << 2) -+#define PRP_INTR_ST_CH2B2CI (1 << 3) -+#define PRP_INTR_ST_CH2B1CI (1 << 4) -+#define PRP_INTR_ST_CH1B2CI (1 << 5) -+#define PRP_INTR_ST_CH1B1CI (1 << 6) -+#define PRP_INTR_ST_LBOVF (1 << 7) -+#define PRP_INTR_ST_CH2OVF (1 << 8) -+ -+struct emmaprp_fmt { -+ char *name; -+ u32 fourcc; -+ /* Types the format can be used for */ -+ u32 types; -+}; -+ -+static struct emmaprp_fmt formats[] = { -+ { -+ .name = "YUV 4:2:0 Planar", -+ .fourcc = V4L2_PIX_FMT_YUV420, -+ .types = MEM2MEM_CAPTURE, -+ }, -+ { -+ .name = "4:2:2, packed, YUYV", -+ .fourcc = V4L2_PIX_FMT_YUYV, -+ .types = MEM2MEM_OUTPUT, -+ }, -+}; -+ -+/* Per-queue, driver-specific private data */ -+struct emmaprp_q_data { -+ unsigned int width; -+ unsigned int height; -+ unsigned int sizeimage; -+ struct emmaprp_fmt *fmt; -+}; -+ -+enum { -+ V4L2_M2M_SRC = 0, -+ V4L2_M2M_DST = 1, -+}; -+ -+#define NUM_FORMATS ARRAY_SIZE(formats) -+ -+static struct emmaprp_fmt *find_format(struct v4l2_format *f) -+{ -+ struct emmaprp_fmt *fmt; -+ unsigned int k; -+ -+ for (k = 0; k < NUM_FORMATS; k++) { -+ fmt = &formats[k]; -+ if (fmt->fourcc == f->fmt.pix.pixelformat) -+ break; -+ } -+ -+ if (k == NUM_FORMATS) -+ return NULL; -+ -+ return &formats[k]; -+} -+ -+struct emmaprp_dev { -+ struct v4l2_device v4l2_dev; -+ struct video_device *vfd; -+ -+ struct mutex dev_mutex; -+ spinlock_t irqlock; -+ -+ int irq_emma; -+ void __iomem *base_emma; -+ struct clk *clk_emma; -+ struct resource *res_emma; -+ -+ struct v4l2_m2m_dev *m2m_dev; -+ struct vb2_alloc_ctx *alloc_ctx; -+}; -+ -+struct emmaprp_ctx { -+ struct emmaprp_dev *dev; -+ /* Abort requested by m2m */ -+ int aborting; -+ struct emmaprp_q_data q_data[2]; -+ struct v4l2_m2m_ctx *m2m_ctx; -+}; -+ -+static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx, -+ enum v4l2_buf_type type) -+{ -+ switch (type) { -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT: -+ return &(ctx->q_data[V4L2_M2M_SRC]); -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: -+ return &(ctx->q_data[V4L2_M2M_DST]); -+ default: -+ BUG(); -+ } -+ return NULL; -+} -+ -+/* -+ * mem2mem callbacks -+ */ -+static void emmaprp_job_abort(void *priv) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ struct emmaprp_dev *pcdev = ctx->dev; -+ -+ ctx->aborting = 1; -+ -+ dprintk(pcdev, "Aborting task\n"); -+ -+ v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); -+} -+ -+static void emmaprp_lock(void *priv) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ struct emmaprp_dev *pcdev = ctx->dev; -+ mutex_lock(&pcdev->dev_mutex); -+} -+ -+static void emmaprp_unlock(void *priv) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ struct emmaprp_dev *pcdev = ctx->dev; -+ mutex_unlock(&pcdev->dev_mutex); -+} -+ -+static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev) -+{ -+ dprintk(pcdev, -+ "eMMa-PrP Registers:\n" -+ " SOURCE_Y_PTR = 0x%08X\n" -+ " SRC_FRAME_SIZE = 0x%08X\n" -+ " DEST_Y_PTR = 0x%08X\n" -+ " DEST_CR_PTR = 0x%08X\n" -+ " DEST_CB_PTR = 0x%08X\n" -+ " CH2_OUT_IMAGE_SIZE = 0x%08X\n" -+ " CNTL = 0x%08X\n", -+ readl(pcdev->base_emma + PRP_SOURCE_Y_PTR), -+ readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE), -+ readl(pcdev->base_emma + PRP_DEST_Y_PTR), -+ readl(pcdev->base_emma + PRP_DEST_CR_PTR), -+ readl(pcdev->base_emma + PRP_DEST_CB_PTR), -+ readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE), -+ readl(pcdev->base_emma + PRP_CNTL)); -+} -+ -+static void emmaprp_device_run(void *priv) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ struct emmaprp_q_data *s_q_data, *d_q_data; -+ struct vb2_buffer *src_buf, *dst_buf; -+ struct emmaprp_dev *pcdev = ctx->dev; -+ unsigned int s_width, s_height; -+ unsigned int d_width, d_height; -+ unsigned int d_size; -+ dma_addr_t p_in, p_out; -+ u32 tmp; -+ -+ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); -+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); -+ -+ s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); -+ s_width = s_q_data->width; -+ s_height = s_q_data->height; -+ -+ d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); -+ d_width = d_q_data->width; -+ d_height = d_q_data->height; -+ d_size = d_width * d_height; -+ -+ p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0); -+ p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0); -+ if (!p_in || !p_out) { -+ v4l2_err(&pcdev->v4l2_dev, -+ "Acquiring kernel pointers to buffers failed\n"); -+ return; -+ } -+ -+ /* Input frame parameters */ -+ writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR); -+ writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height), -+ pcdev->base_emma + PRP_SRC_FRAME_SIZE); -+ -+ /* Output frame parameters */ -+ writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR); -+ writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR); -+ writel(p_out + d_size + (d_size >> 2), -+ pcdev->base_emma + PRP_DEST_CR_PTR); -+ writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height), -+ pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); -+ -+ /* IRQ configuration */ -+ tmp = readl(pcdev->base_emma + PRP_INTR_CNTL); -+ writel(tmp | PRP_INTR_RDERR | -+ PRP_INTR_CH2WERR | -+ PRP_INTR_CH2FC, -+ pcdev->base_emma + PRP_INTR_CNTL); -+ -+ emmaprp_dump_regs(pcdev); -+ -+ /* Enable transfer */ -+ tmp = readl(pcdev->base_emma + PRP_CNTL); -+ writel(tmp | PRP_CNTL_CH2_OUT_YUV420 | -+ PRP_CNTL_DATA_IN_YUV422 | -+ PRP_CNTL_CH2EN, -+ pcdev->base_emma + PRP_CNTL); -+} -+ -+static irqreturn_t emmaprp_irq(int irq_emma, void *data) -+{ -+ struct emmaprp_dev *pcdev = data; -+ struct emmaprp_ctx *curr_ctx; -+ struct vb2_buffer *src_vb, *dst_vb; -+ unsigned long flags; -+ u32 irqst; -+ -+ /* Check irq flags and clear irq */ -+ irqst = readl(pcdev->base_emma + PRP_INTRSTATUS); -+ writel(irqst, pcdev->base_emma + PRP_INTRSTATUS); -+ dprintk(pcdev, "irqst = 0x%08x\n", irqst); -+ -+ curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev); -+ if (curr_ctx == NULL) { -+ pr_err("Instance released before the end of transaction\n"); -+ return IRQ_HANDLED; -+ } -+ -+ if (!curr_ctx->aborting) { -+ if ((irqst & PRP_INTR_ST_RDERR) || -+ (irqst & PRP_INTR_ST_CH2WERR)) { -+ pr_err("PrP bus error ocurred, this transfer is probably corrupted\n"); -+ writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); -+ } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */ -+ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); -+ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); -+ -+ spin_lock_irqsave(&pcdev->irqlock, flags); -+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); -+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); -+ spin_unlock_irqrestore(&pcdev->irqlock, flags); -+ } -+ } -+ -+ v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); -+ return IRQ_HANDLED; -+} -+ -+/* -+ * video ioctls -+ */ -+static int vidioc_querycap(struct file *file, void *priv, -+ struct v4l2_capability *cap) -+{ -+ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); -+ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); -+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT -+ | V4L2_CAP_STREAMING; -+ -+ return 0; -+} -+ -+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) -+{ -+ int i, num; -+ struct emmaprp_fmt *fmt; -+ -+ num = 0; -+ -+ for (i = 0; i < NUM_FORMATS; ++i) { -+ if (formats[i].types & type) { -+ /* index-th format of type type found ? */ -+ if (num == f->index) -+ break; -+ /* Correct type but haven't reached our index yet, -+ * just increment per-type index */ -+ ++num; -+ } -+ } -+ -+ if (i < NUM_FORMATS) { -+ /* Format found */ -+ fmt = &formats[i]; -+ strlcpy(f->description, fmt->name, sizeof(f->description) - 1); -+ f->pixelformat = fmt->fourcc; -+ return 0; -+ } -+ -+ /* Format not found */ -+ return -EINVAL; -+} -+ -+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_fmtdesc *f) -+{ -+ return enum_fmt(f, MEM2MEM_CAPTURE); -+} -+ -+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, -+ struct v4l2_fmtdesc *f) -+{ -+ return enum_fmt(f, MEM2MEM_OUTPUT); -+} -+ -+static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) -+{ -+ struct vb2_queue *vq; -+ struct emmaprp_q_data *q_data; -+ -+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); -+ if (!vq) -+ return -EINVAL; -+ -+ q_data = get_q_data(ctx, f->type); -+ -+ f->fmt.pix.width = q_data->width; -+ f->fmt.pix.height = q_data->height; -+ f->fmt.pix.field = V4L2_FIELD_NONE; -+ f->fmt.pix.pixelformat = q_data->fmt->fourcc; -+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) -+ f->fmt.pix.bytesperline = q_data->width * 3 / 2; -+ else /* YUYV */ -+ f->fmt.pix.bytesperline = q_data->width * 2; -+ f->fmt.pix.sizeimage = q_data->sizeimage; -+ -+ return 0; -+} -+ -+static int vidioc_g_fmt_vid_out(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ return vidioc_g_fmt(priv, f); -+} -+ -+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ return vidioc_g_fmt(priv, f); -+} -+ -+static int vidioc_try_fmt(struct v4l2_format *f) -+{ -+ enum v4l2_field field; -+ -+ -+ if (!find_format(f)) -+ return -EINVAL; -+ -+ field = f->fmt.pix.field; -+ if (field == V4L2_FIELD_ANY) -+ field = V4L2_FIELD_NONE; -+ else if (V4L2_FIELD_NONE != field) -+ return -EINVAL; -+ -+ /* V4L2 specification suggests the driver corrects the format struct -+ * if any of the dimensions is unsupported */ -+ f->fmt.pix.field = field; -+ -+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) { -+ v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, -+ W_ALIGN_YUV420, &f->fmt.pix.height, -+ MIN_H, MAX_H, H_ALIGN, S_ALIGN); -+ f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2; -+ } else { -+ v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, -+ W_ALIGN_OTHERS, &f->fmt.pix.height, -+ MIN_H, MAX_H, H_ALIGN, S_ALIGN); -+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2; -+ } -+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; -+ -+ return 0; -+} -+ -+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ struct emmaprp_fmt *fmt; -+ struct emmaprp_ctx *ctx = priv; -+ -+ fmt = find_format(f); -+ if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { -+ v4l2_err(&ctx->dev->v4l2_dev, -+ "Fourcc format (0x%08x) invalid.\n", -+ f->fmt.pix.pixelformat); -+ return -EINVAL; -+ } -+ -+ return vidioc_try_fmt(f); -+} -+ -+static int vidioc_try_fmt_vid_out(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ struct emmaprp_fmt *fmt; -+ struct emmaprp_ctx *ctx = priv; -+ -+ fmt = find_format(f); -+ if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { -+ v4l2_err(&ctx->dev->v4l2_dev, -+ "Fourcc format (0x%08x) invalid.\n", -+ f->fmt.pix.pixelformat); -+ return -EINVAL; -+ } -+ -+ return vidioc_try_fmt(f); -+} -+ -+static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) -+{ -+ struct emmaprp_q_data *q_data; -+ struct vb2_queue *vq; -+ int ret; -+ -+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); -+ if (!vq) -+ return -EINVAL; -+ -+ q_data = get_q_data(ctx, f->type); -+ if (!q_data) -+ return -EINVAL; -+ -+ if (vb2_is_busy(vq)) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); -+ return -EBUSY; -+ } -+ -+ ret = vidioc_try_fmt(f); -+ if (ret) -+ return ret; -+ -+ q_data->fmt = find_format(f); -+ q_data->width = f->fmt.pix.width; -+ q_data->height = f->fmt.pix.height; -+ if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) -+ q_data->sizeimage = q_data->width * q_data->height * 3 / 2; -+ else /* YUYV */ -+ q_data->sizeimage = q_data->width * q_data->height * 2; -+ -+ dprintk(ctx->dev, -+ "Setting format for type %d, wxh: %dx%d, fmt: %d\n", -+ f->type, q_data->width, q_data->height, q_data->fmt->fourcc); -+ -+ return 0; -+} -+ -+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ int ret; -+ -+ ret = vidioc_try_fmt_vid_cap(file, priv, f); -+ if (ret) -+ return ret; -+ -+ return vidioc_s_fmt(priv, f); -+} -+ -+static int vidioc_s_fmt_vid_out(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ int ret; -+ -+ ret = vidioc_try_fmt_vid_out(file, priv, f); -+ if (ret) -+ return ret; -+ -+ return vidioc_s_fmt(priv, f); -+} -+ -+static int vidioc_reqbufs(struct file *file, void *priv, -+ struct v4l2_requestbuffers *reqbufs) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ -+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -+} -+ -+static int vidioc_querybuf(struct file *file, void *priv, -+ struct v4l2_buffer *buf) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ -+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -+} -+ -+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ -+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -+} -+ -+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ -+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -+} -+ -+static int vidioc_streamon(struct file *file, void *priv, -+ enum v4l2_buf_type type) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ -+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -+} -+ -+static int vidioc_streamoff(struct file *file, void *priv, -+ enum v4l2_buf_type type) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ -+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); -+} -+ -+static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { -+ .vidioc_querycap = vidioc_querycap, -+ -+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, -+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, -+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, -+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, -+ -+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, -+ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, -+ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, -+ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, -+ -+ .vidioc_reqbufs = vidioc_reqbufs, -+ .vidioc_querybuf = vidioc_querybuf, -+ -+ .vidioc_qbuf = vidioc_qbuf, -+ .vidioc_dqbuf = vidioc_dqbuf, -+ -+ .vidioc_streamon = vidioc_streamon, -+ .vidioc_streamoff = vidioc_streamoff, -+}; -+ -+ -+/* -+ * Queue operations -+ */ -+static int emmaprp_queue_setup(struct vb2_queue *vq, -+ const struct v4l2_format *fmt, -+ unsigned int *nbuffers, unsigned int *nplanes, -+ unsigned int sizes[], void *alloc_ctxs[]) -+{ -+ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq); -+ struct emmaprp_q_data *q_data; -+ unsigned int size, count = *nbuffers; -+ -+ q_data = get_q_data(ctx, vq->type); -+ -+ if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) -+ size = q_data->width * q_data->height * 3 / 2; -+ else -+ size = q_data->width * q_data->height * 2; -+ -+ while (size * count > MEM2MEM_VID_MEM_LIMIT) -+ (count)--; -+ -+ *nplanes = 1; -+ *nbuffers = count; -+ sizes[0] = size; -+ -+ alloc_ctxs[0] = ctx->dev->alloc_ctx; -+ -+ dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); -+ -+ return 0; -+} -+ -+static int emmaprp_buf_prepare(struct vb2_buffer *vb) -+{ -+ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); -+ struct emmaprp_q_data *q_data; -+ -+ dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); -+ -+ q_data = get_q_data(ctx, vb->vb2_queue->type); -+ -+ if (vb2_plane_size(vb, 0) < q_data->sizeimage) { -+ dprintk(ctx->dev, "%s data will not fit into plane" -+ "(%lu < %lu)\n", __func__, -+ vb2_plane_size(vb, 0), -+ (long)q_data->sizeimage); -+ return -EINVAL; -+ } -+ -+ vb2_set_plane_payload(vb, 0, q_data->sizeimage); -+ -+ return 0; -+} -+ -+static void emmaprp_buf_queue(struct vb2_buffer *vb) -+{ -+ struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); -+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); -+} -+ -+static struct vb2_ops emmaprp_qops = { -+ .queue_setup = emmaprp_queue_setup, -+ .buf_prepare = emmaprp_buf_prepare, -+ .buf_queue = emmaprp_buf_queue, -+}; -+ -+static int queue_init(void *priv, struct vb2_queue *src_vq, -+ struct vb2_queue *dst_vq) -+{ -+ struct emmaprp_ctx *ctx = priv; -+ int ret; -+ -+ memset(src_vq, 0, sizeof(*src_vq)); -+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; -+ src_vq->io_modes = VB2_MMAP; -+ src_vq->drv_priv = ctx; -+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); -+ src_vq->ops = &emmaprp_qops; -+ src_vq->mem_ops = &vb2_dma_contig_memops; -+ -+ ret = vb2_queue_init(src_vq); -+ if (ret) -+ return ret; -+ -+ memset(dst_vq, 0, sizeof(*dst_vq)); -+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ dst_vq->io_modes = VB2_MMAP; -+ dst_vq->drv_priv = ctx; -+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); -+ dst_vq->ops = &emmaprp_qops; -+ dst_vq->mem_ops = &vb2_dma_contig_memops; -+ -+ return vb2_queue_init(dst_vq); -+} -+ -+/* -+ * File operations -+ */ -+static int emmaprp_open(struct file *file) -+{ -+ struct emmaprp_dev *pcdev = video_drvdata(file); -+ struct emmaprp_ctx *ctx; -+ -+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL); -+ if (!ctx) -+ return -ENOMEM; -+ -+ file->private_data = ctx; -+ ctx->dev = pcdev; -+ -+ ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); -+ -+ if (IS_ERR(ctx->m2m_ctx)) { -+ int ret = PTR_ERR(ctx->m2m_ctx); -+ -+ kfree(ctx); -+ return ret; -+ } -+ -+ clk_enable(pcdev->clk_emma); -+ ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; -+ ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; -+ -+ dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); -+ -+ return 0; -+} -+ -+static int emmaprp_release(struct file *file) -+{ -+ struct emmaprp_dev *pcdev = video_drvdata(file); -+ struct emmaprp_ctx *ctx = file->private_data; -+ -+ dprintk(pcdev, "Releasing instance %p\n", ctx); -+ -+ clk_disable(pcdev->clk_emma); -+ v4l2_m2m_ctx_release(ctx->m2m_ctx); -+ kfree(ctx); -+ -+ return 0; -+} -+ -+static unsigned int emmaprp_poll(struct file *file, -+ struct poll_table_struct *wait) -+{ -+ struct emmaprp_ctx *ctx = file->private_data; -+ -+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); -+} -+ -+static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ struct emmaprp_ctx *ctx = file->private_data; -+ -+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); -+} -+ -+static const struct v4l2_file_operations emmaprp_fops = { -+ .owner = THIS_MODULE, -+ .open = emmaprp_open, -+ .release = emmaprp_release, -+ .poll = emmaprp_poll, -+ .unlocked_ioctl = video_ioctl2, -+ .mmap = emmaprp_mmap, -+}; -+ -+static struct video_device emmaprp_videodev = { -+ .name = MEM2MEM_NAME, -+ .fops = &emmaprp_fops, -+ .ioctl_ops = &emmaprp_ioctl_ops, -+ .minor = -1, -+ .release = video_device_release, -+}; -+ -+static struct v4l2_m2m_ops m2m_ops = { -+ .device_run = emmaprp_device_run, -+ .job_abort = emmaprp_job_abort, -+ .lock = emmaprp_lock, -+ .unlock = emmaprp_unlock, -+}; -+ -+static int emmaprp_probe(struct platform_device *pdev) -+{ -+ struct emmaprp_dev *pcdev; -+ struct video_device *vfd; -+ struct resource *res_emma; -+ int irq_emma; -+ int ret; -+ -+ pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL); -+ if (!pcdev) -+ return -ENOMEM; -+ -+ spin_lock_init(&pcdev->irqlock); -+ -+ pcdev->clk_emma = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(pcdev->clk_emma)) { -+ ret = PTR_ERR(pcdev->clk_emma); -+ goto free_dev; -+ } -+ -+ irq_emma = platform_get_irq(pdev, 0); -+ res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (irq_emma < 0 || res_emma == NULL) { -+ dev_err(&pdev->dev, "Missing platform resources data\n"); -+ ret = -ENODEV; -+ goto free_clk; -+ } -+ -+ ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); -+ if (ret) -+ goto free_clk; -+ -+ mutex_init(&pcdev->dev_mutex); -+ -+ vfd = video_device_alloc(); -+ if (!vfd) { -+ v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n"); -+ ret = -ENOMEM; -+ goto unreg_dev; -+ } -+ -+ *vfd = emmaprp_videodev; -+ vfd->lock = &pcdev->dev_mutex; -+ -+ video_set_drvdata(vfd, pcdev); -+ snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name); -+ pcdev->vfd = vfd; -+ v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME -+ " Device registered as /dev/video%d\n", vfd->num); -+ -+ platform_set_drvdata(pdev, pcdev); -+ -+ if (devm_request_mem_region(&pdev->dev, res_emma->start, -+ resource_size(res_emma), MEM2MEM_NAME) == NULL) -+ goto rel_vdev; -+ -+ pcdev->base_emma = devm_ioremap(&pdev->dev, res_emma->start, -+ resource_size(res_emma)); -+ if (!pcdev->base_emma) -+ goto rel_vdev; -+ -+ pcdev->irq_emma = irq_emma; -+ pcdev->res_emma = res_emma; -+ -+ if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq, -+ 0, MEM2MEM_NAME, pcdev) < 0) -+ goto rel_vdev; -+ -+ pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); -+ if (IS_ERR(pcdev->alloc_ctx)) { -+ v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n"); -+ ret = PTR_ERR(pcdev->alloc_ctx); -+ goto rel_vdev; -+ } -+ -+ pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops); -+ if (IS_ERR(pcdev->m2m_dev)) { -+ v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n"); -+ ret = PTR_ERR(pcdev->m2m_dev); -+ goto rel_ctx; -+ } -+ -+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); -+ if (ret) { -+ v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); -+ goto rel_m2m; -+ } -+ -+ return 0; -+ -+ -+rel_m2m: -+ v4l2_m2m_release(pcdev->m2m_dev); -+rel_ctx: -+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); -+rel_vdev: -+ video_device_release(vfd); -+unreg_dev: -+ v4l2_device_unregister(&pcdev->v4l2_dev); -+free_clk: -+ clk_put(pcdev->clk_emma); -+free_dev: -+ kfree(pcdev); -+ -+ return ret; -+} -+ -+static int emmaprp_remove(struct platform_device *pdev) -+{ -+ struct emmaprp_dev *pcdev = platform_get_drvdata(pdev); -+ -+ v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME); -+ -+ video_unregister_device(pcdev->vfd); -+ v4l2_m2m_release(pcdev->m2m_dev); -+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); -+ v4l2_device_unregister(&pcdev->v4l2_dev); -+ clk_put(pcdev->clk_emma); -+ kfree(pcdev); -+ -+ return 0; -+} -+ -+static struct platform_driver emmaprp_pdrv = { -+ .probe = emmaprp_probe, -+ .remove = emmaprp_remove, -+ .driver = { -+ .name = MEM2MEM_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static void __exit emmaprp_exit(void) -+{ -+ platform_driver_unregister(&emmaprp_pdrv); -+} -+ -+static int __init emmaprp_init(void) -+{ -+ return platform_driver_register(&emmaprp_pdrv); -+} -+ -+module_init(emmaprp_init); -+module_exit(emmaprp_exit); -Index: linux-3.3.x86_64/drivers/media/common/tuners/mt2063.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/common/tuners/mt2063.h -+++ linux-3.3.x86_64/drivers/media/common/tuners/mt2063.h -@@ -23,10 +23,6 @@ static inline struct dvb_frontend *mt206 - return NULL; - } - --int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, -- u32 bw_in, -- enum MTTune_atv_standard tv_type); -- - /* FIXME: Should use the standard DVB attachment interfaces */ - unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); - unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); -Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/sdo_drv.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/sdo_drv.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-tv/sdo_drv.c -@@ -301,7 +301,7 @@ static int __devinit sdo_probe(struct pl - struct clk *sclk_vpll; - - dev_info(dev, "probe start\n"); -- sdev = kzalloc(sizeof *sdev, GFP_KERNEL); -+ sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL); - if (!sdev) { - dev_err(dev, "not enough memory.\n"); - ret = -ENOMEM; -@@ -314,14 +314,14 @@ static int __devinit sdo_probe(struct pl - if (res == NULL) { - dev_err(dev, "get memory resource failed.\n"); - ret = -ENXIO; -- goto fail_sdev; -+ goto fail; - } - -- sdev->regs = ioremap(res->start, resource_size(res)); -+ sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (sdev->regs == NULL) { - dev_err(dev, "register mapping failed.\n"); - ret = -ENXIO; -- goto fail_sdev; -+ goto fail; - } - - /* acquiring interrupt */ -@@ -329,12 +329,13 @@ static int __devinit sdo_probe(struct pl - if (res == NULL) { - dev_err(dev, "get interrupt resource failed.\n"); - ret = -ENXIO; -- goto fail_regs; -+ goto fail; - } -- ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev); -+ ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0, -+ "s5p-sdo", sdev); - if (ret) { - dev_err(dev, "request interrupt failed.\n"); -- goto fail_regs; -+ goto fail; - } - sdev->irq = res->start; - -@@ -343,7 +344,7 @@ static int __devinit sdo_probe(struct pl - if (IS_ERR_OR_NULL(sdev->sclk_dac)) { - dev_err(dev, "failed to get clock 'sclk_dac'\n"); - ret = -ENXIO; -- goto fail_irq; -+ goto fail; - } - sdev->dac = clk_get(dev, "dac"); - if (IS_ERR_OR_NULL(sdev->dac)) { -@@ -415,12 +416,6 @@ fail_dac: - clk_put(sdev->dac); - fail_sclk_dac: - clk_put(sdev->sclk_dac); --fail_irq: -- free_irq(sdev->irq, sdev); --fail_regs: -- iounmap(sdev->regs); --fail_sdev: -- kfree(sdev); - fail: - dev_info(dev, "probe failed\n"); - return ret; -@@ -439,9 +434,6 @@ static int __devexit sdo_remove(struct p - clk_put(sdev->dacphy); - clk_put(sdev->dac); - clk_put(sdev->sclk_dac); -- free_irq(sdev->irq, sdev); -- iounmap(sdev->regs); -- kfree(sdev); - - dev_info(&pdev->dev, "remove successful\n"); - return 0; -Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/Kconfig -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/Kconfig -+++ linux-3.3.x86_64/drivers/media/video/s5p-tv/Kconfig -@@ -46,6 +46,16 @@ config VIDEO_SAMSUNG_S5P_HDMIPHY - as module. It is an I2C driver, that exposes a V4L2 - subdev for use by other drivers. - -+config VIDEO_SAMSUNG_S5P_SII9234 -+ tristate "Samsung SII9234 Driver" -+ depends on VIDEO_DEV && VIDEO_V4L2 && I2C -+ depends on VIDEO_SAMSUNG_S5P_TV -+ help -+ Say Y here if you want support for the MHL interface -+ in S5P Samsung SoC. The driver can be compiled -+ as module. It is an I2C driver, that exposes a V4L2 -+ subdev for use by other drivers. -+ - config VIDEO_SAMSUNG_S5P_SDO - tristate "Samsung Analog TV Driver" - depends on VIDEO_DEV && VIDEO_V4L2 -Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/Makefile -+++ linux-3.3.x86_64/drivers/media/video/s5p-tv/Makefile -@@ -8,6 +8,8 @@ - - obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o - s5p-hdmiphy-y += hdmiphy_drv.o -+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o -+s5p-sii9234-y += sii9234_drv.o - obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o - s5p-hdmi-y += hdmi_drv.o - obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o -Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/sii9234_drv.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/s5p-tv/sii9234_drv.c -@@ -0,0 +1,432 @@ -+/* -+ * Samsung MHL interface driver -+ * -+ * Copyright (C) 2011 Samsung Electronics Co.Ltd -+ * Author: Tomasz Stanislawski -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+MODULE_AUTHOR("Tomasz Stanislawski "); -+MODULE_DESCRIPTION("Samsung MHL interface driver"); -+MODULE_LICENSE("GPL"); -+ -+struct sii9234_context { -+ struct i2c_client *client; -+ struct regulator *power; -+ int gpio_n_reset; -+ struct v4l2_subdev sd; -+}; -+ -+static inline struct sii9234_context *sd_to_context(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct sii9234_context, sd); -+} -+ -+static inline int sii9234_readb(struct i2c_client *client, int addr) -+{ -+ return i2c_smbus_read_byte_data(client, addr); -+} -+ -+static inline int sii9234_writeb(struct i2c_client *client, int addr, int value) -+{ -+ return i2c_smbus_write_byte_data(client, addr, value); -+} -+ -+static inline int sii9234_writeb_mask(struct i2c_client *client, int addr, -+ int value, int mask) -+{ -+ int ret; -+ -+ ret = i2c_smbus_read_byte_data(client, addr); -+ if (ret < 0) -+ return ret; -+ ret = (ret & ~mask) | (value & mask); -+ return i2c_smbus_write_byte_data(client, addr, ret); -+} -+ -+static inline int sii9234_readb_idx(struct i2c_client *client, int addr) -+{ -+ int ret; -+ ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8); -+ if (ret < 0) -+ return ret; -+ ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff); -+ if (ret < 0) -+ return ret; -+ return i2c_smbus_read_byte_data(client, 0xbe); -+} -+ -+static inline int sii9234_writeb_idx(struct i2c_client *client, int addr, -+ int value) -+{ -+ int ret; -+ ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8); -+ if (ret < 0) -+ return ret; -+ ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff); -+ if (ret < 0) -+ return ret; -+ ret = i2c_smbus_write_byte_data(client, 0xbe, value); -+ return ret; -+} -+ -+static inline int sii9234_writeb_idx_mask(struct i2c_client *client, int addr, -+ int value, int mask) -+{ -+ int ret; -+ -+ ret = sii9234_readb_idx(client, addr); -+ if (ret < 0) -+ return ret; -+ ret = (ret & ~mask) | (value & mask); -+ return sii9234_writeb_idx(client, addr, ret); -+} -+ -+static int sii9234_reset(struct sii9234_context *ctx) -+{ -+ struct i2c_client *client = ctx->client; -+ struct device *dev = &client->dev; -+ int ret, tries; -+ -+ gpio_direction_output(ctx->gpio_n_reset, 1); -+ mdelay(1); -+ gpio_direction_output(ctx->gpio_n_reset, 0); -+ mdelay(1); -+ gpio_direction_output(ctx->gpio_n_reset, 1); -+ mdelay(1); -+ -+ /* going to TTPI mode */ -+ ret = sii9234_writeb(client, 0xc7, 0); -+ if (ret < 0) { -+ dev_err(dev, "failed to set TTPI mode\n"); -+ return ret; -+ } -+ for (tries = 0; tries < 100 ; ++tries) { -+ ret = sii9234_readb(client, 0x1b); -+ if (ret > 0) -+ break; -+ if (ret < 0) { -+ dev_err(dev, "failed to reset device\n"); -+ return -EIO; -+ } -+ mdelay(1); -+ } -+ if (tries == 100) { -+ dev_err(dev, "maximal number of tries reached\n"); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int sii9234_verify_version(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ int family, rev, tpi_rev, dev_id, sub_id, hdcp, id; -+ -+ family = sii9234_readb(client, 0x1b); -+ rev = sii9234_readb(client, 0x1c) & 0x0f; -+ tpi_rev = sii9234_readb(client, 0x1d) & 0x7f; -+ dev_id = sii9234_readb_idx(client, 0x0103); -+ sub_id = sii9234_readb_idx(client, 0x0102); -+ hdcp = sii9234_readb(client, 0x30); -+ -+ if (family < 0 || rev < 0 || tpi_rev < 0 || dev_id < 0 || -+ sub_id < 0 || hdcp < 0) { -+ dev_err(dev, "failed to read chip's version\n"); -+ return -EIO; -+ } -+ -+ id = (dev_id << 8) | sub_id; -+ -+ dev_info(dev, "chip: SiL%02x family: %02x, rev: %02x\n", -+ id, family, rev); -+ dev_info(dev, "tpi_rev:%02x, hdcp: %02x\n", tpi_rev, hdcp); -+ if (id != 0x9234) { -+ dev_err(dev, "not supported chip\n"); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static u8 data[][3] = { -+/* setup from driver created by doonsoo45.kim */ -+ { 0x01, 0x05, 0x04 }, /* Enable Auto soft reset on SCDT = 0 */ -+ { 0x01, 0x08, 0x35 }, /* Power Up TMDS Tx Core */ -+ { 0x01, 0x0d, 0x1c }, /* HDMI Transcode mode enable */ -+ { 0x01, 0x2b, 0x01 }, /* Enable HDCP Compliance workaround */ -+ { 0x01, 0x79, 0x40 }, /* daniel test...MHL_INT */ -+ { 0x01, 0x80, 0x34 }, /* Enable Rx PLL Clock Value */ -+ { 0x01, 0x90, 0x27 }, /* Enable CBUS discovery */ -+ { 0x01, 0x91, 0xe5 }, /* Skip RGND detection */ -+ { 0x01, 0x92, 0x46 }, /* Force MHD mode */ -+ { 0x01, 0x93, 0xdc }, /* Disable CBUS pull-up during RGND measurement */ -+ { 0x01, 0x94, 0x66 }, /* 1.8V CBUS VTH & GND threshold */ -+ { 0x01, 0x95, 0x31 }, /* RGND block & single discovery attempt */ -+ { 0x01, 0x96, 0x22 }, /* use 1K and 2K setting */ -+ { 0x01, 0xa0, 0x10 }, /* SIMG: Term mode */ -+ { 0x01, 0xa1, 0xfc }, /* Disable internal Mobile HD driver */ -+ { 0x01, 0xa3, 0xfa }, /* SIMG: Output Swing default EB, 3x Clk Mult */ -+ { 0x01, 0xa5, 0x80 }, /* SIMG: RGND Hysterisis, 3x mode for Beast */ -+ { 0x01, 0xa6, 0x0c }, /* SIMG: Swing Offset */ -+ { 0x02, 0x3d, 0x3f }, /* Power up CVCC 1.2V core */ -+ { 0x03, 0x00, 0x00 }, /* SIMG: correcting HW default */ -+ { 0x03, 0x11, 0x01 }, /* Enable TxPLL Clock */ -+ { 0x03, 0x12, 0x15 }, /* Enable Tx Clock Path & Equalizer */ -+ { 0x03, 0x13, 0x60 }, /* SIMG: Set termination value */ -+ { 0x03, 0x14, 0xf0 }, /* SIMG: Change CKDT level */ -+ { 0x03, 0x17, 0x07 }, /* SIMG: PLL Calrefsel */ -+ { 0x03, 0x1a, 0x20 }, /* VCO Cal */ -+ { 0x03, 0x22, 0xe0 }, /* SIMG: Auto EQ */ -+ { 0x03, 0x23, 0xc0 }, /* SIMG: Auto EQ */ -+ { 0x03, 0x24, 0xa0 }, /* SIMG: Auto EQ */ -+ { 0x03, 0x25, 0x80 }, /* SIMG: Auto EQ */ -+ { 0x03, 0x26, 0x60 }, /* SIMG: Auto EQ */ -+ { 0x03, 0x27, 0x40 }, /* SIMG: Auto EQ */ -+ { 0x03, 0x28, 0x20 }, /* SIMG: Auto EQ */ -+ { 0x03, 0x29, 0x00 }, /* SIMG: Auto EQ */ -+ { 0x03, 0x31, 0x0b }, /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz */ -+ { 0x03, 0x45, 0x06 }, /* SIMG: DPLL Mode */ -+ { 0x03, 0x4b, 0x06 }, /* SIMG: Correcting HW default */ -+ { 0x03, 0x4c, 0xa0 }, /* Manual zone control */ -+ { 0x03, 0x4d, 0x02 }, /* SIMG: PLL Mode Value (order is important) */ -+}; -+ -+static int sii9234_set_internal(struct sii9234_context *ctx) -+{ -+ struct i2c_client *client = ctx->client; -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(data); ++i) { -+ int addr = (data[i][0] << 8) | data[i][1]; -+ ret = sii9234_writeb_idx(client, addr, data[i][2]); -+ if (ret < 0) -+ return ret; -+ } -+ return 0; -+} -+ -+static int sii9234_runtime_suspend(struct device *dev) -+{ -+ struct v4l2_subdev *sd = dev_get_drvdata(dev); -+ struct sii9234_context *ctx = sd_to_context(sd); -+ struct i2c_client *client = ctx->client; -+ -+ dev_info(dev, "suspend start\n"); -+ -+ sii9234_writeb_mask(client, 0x1e, 3, 3); -+ regulator_disable(ctx->power); -+ -+ return 0; -+} -+ -+static int sii9234_runtime_resume(struct device *dev) -+{ -+ struct v4l2_subdev *sd = dev_get_drvdata(dev); -+ struct sii9234_context *ctx = sd_to_context(sd); -+ struct i2c_client *client = ctx->client; -+ int ret; -+ -+ dev_info(dev, "resume start\n"); -+ regulator_enable(ctx->power); -+ -+ ret = sii9234_reset(ctx); -+ if (ret) -+ goto fail; -+ -+ /* enable tpi */ -+ ret = sii9234_writeb_mask(client, 0x1e, 1, 0); -+ if (ret < 0) -+ goto fail; -+ ret = sii9234_set_internal(ctx); -+ if (ret < 0) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ dev_err(dev, "failed to resume\n"); -+ regulator_disable(ctx->power); -+ -+ return ret; -+} -+ -+static const struct dev_pm_ops sii9234_pm_ops = { -+ .runtime_suspend = sii9234_runtime_suspend, -+ .runtime_resume = sii9234_runtime_resume, -+}; -+ -+static int sii9234_s_power(struct v4l2_subdev *sd, int on) -+{ -+ struct sii9234_context *ctx = sd_to_context(sd); -+ int ret; -+ -+ if (on) -+ ret = pm_runtime_get_sync(&ctx->client->dev); -+ else -+ ret = pm_runtime_put(&ctx->client->dev); -+ /* only values < 0 indicate errors */ -+ return IS_ERR_VALUE(ret) ? ret : 0; -+} -+ -+static int sii9234_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct sii9234_context *ctx = sd_to_context(sd); -+ -+ /* (dis/en)able TDMS output */ -+ sii9234_writeb_mask(ctx->client, 0x1a, enable ? 0 : ~0 , 1 << 4); -+ return 0; -+} -+ -+static const struct v4l2_subdev_core_ops sii9234_core_ops = { -+ .s_power = sii9234_s_power, -+}; -+ -+static const struct v4l2_subdev_video_ops sii9234_video_ops = { -+ .s_stream = sii9234_s_stream, -+}; -+ -+static const struct v4l2_subdev_ops sii9234_ops = { -+ .core = &sii9234_core_ops, -+ .video = &sii9234_video_ops, -+}; -+ -+static int __devinit sii9234_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct device *dev = &client->dev; -+ struct sii9234_platform_data *pdata = dev->platform_data; -+ struct sii9234_context *ctx; -+ int ret; -+ -+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) { -+ dev_err(dev, "out of memory\n"); -+ ret = -ENOMEM; -+ goto fail; -+ } -+ ctx->client = client; -+ -+ ctx->power = regulator_get(dev, "hdmi-en"); -+ if (IS_ERR(ctx->power)) { -+ dev_err(dev, "failed to acquire regulator hdmi-en\n"); -+ ret = PTR_ERR(ctx->power); -+ goto fail_ctx; -+ } -+ -+ ctx->gpio_n_reset = pdata->gpio_n_reset; -+ ret = gpio_request(ctx->gpio_n_reset, "MHL_RST"); -+ if (ret) { -+ dev_err(dev, "failed to acquire MHL_RST gpio\n"); -+ goto fail_power; -+ } -+ -+ v4l2_i2c_subdev_init(&ctx->sd, client, &sii9234_ops); -+ -+ pm_runtime_enable(dev); -+ -+ /* enable device */ -+ ret = pm_runtime_get_sync(dev); -+ if (ret) -+ goto fail_pm; -+ -+ /* verify chip version */ -+ ret = sii9234_verify_version(client); -+ if (ret) -+ goto fail_pm_get; -+ -+ /* stop processing */ -+ pm_runtime_put(dev); -+ -+ dev_info(dev, "probe successful\n"); -+ -+ return 0; -+ -+fail_pm_get: -+ pm_runtime_put_sync(dev); -+ -+fail_pm: -+ pm_runtime_disable(dev); -+ gpio_free(ctx->gpio_n_reset); -+ -+fail_power: -+ regulator_put(ctx->power); -+ -+fail_ctx: -+ kfree(ctx); -+ -+fail: -+ dev_err(dev, "probe failed\n"); -+ -+ return ret; -+} -+ -+static int __devexit sii9234_remove(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct sii9234_context *ctx = sd_to_context(sd); -+ -+ pm_runtime_disable(dev); -+ gpio_free(ctx->gpio_n_reset); -+ regulator_put(ctx->power); -+ kfree(ctx); -+ -+ dev_info(dev, "remove successful\n"); -+ -+ return 0; -+} -+ -+ -+static const struct i2c_device_id sii9234_id[] = { -+ { "SII9234", 0 }, -+ { }, -+}; -+ -+MODULE_DEVICE_TABLE(i2c, sii9234_id); -+static struct i2c_driver sii9234_driver = { -+ .driver = { -+ .name = "sii9234", -+ .owner = THIS_MODULE, -+ .pm = &sii9234_pm_ops, -+ }, -+ .probe = sii9234_probe, -+ .remove = __devexit_p(sii9234_remove), -+ .id_table = sii9234_id, -+}; -+ -+static int __init sii9234_init(void) -+{ -+ return i2c_add_driver(&sii9234_driver); -+} -+module_init(sii9234_init); -+ -+static void __exit sii9234_exit(void) -+{ -+ i2c_del_driver(&sii9234_driver); -+} -+module_exit(sii9234_exit); -Index: linux-3.3.x86_64/include/media/sii9234.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/include/media/sii9234.h -@@ -0,0 +1,24 @@ -+/* -+ * Driver header for SII9234 MHL converter chip. -+ * -+ * Copyright (c) 2011 Samsung Electronics, Co. Ltd -+ * Contact: Tomasz Stanislawski -+ * -+ * 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. -+ */ -+ -+#ifndef SII9234_H -+#define SII9234_H -+ -+/** -+ * @gpio_n_reset: GPIO driving nRESET pin -+ */ -+ -+struct sii9234_platform_data { -+ int gpio_n_reset; -+}; -+ -+#endif /* SII9234_H */ -Index: linux-3.3.x86_64/include/media/s5p_hdmi.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/include/media/s5p_hdmi.h -@@ -0,0 +1,35 @@ -+/* -+ * Driver header for S5P HDMI chip. -+ * -+ * Copyright (c) 2011 Samsung Electronics, Co. Ltd -+ * Contact: Tomasz Stanislawski -+ * -+ * 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. -+ */ -+ -+#ifndef S5P_HDMI_H -+#define S5P_HDMI_H -+ -+struct i2c_board_info; -+ -+/** -+ * @hdmiphy_bus: controller id for HDMIPHY bus -+ * @hdmiphy_info: template for HDMIPHY I2C device -+ * @mhl_bus: controller id for MHL control bus -+ * @mhl_info: template for MHL I2C device -+ * -+ * NULL pointer for *_info fields indicates that -+ * the corresponding chip is not present -+ */ -+struct s5p_hdmi_platform_data { -+ int hdmiphy_bus; -+ struct i2c_board_info *hdmiphy_info; -+ int mhl_bus; -+ struct i2c_board_info *mhl_info; -+}; -+ -+#endif /* S5P_HDMI_H */ -+ -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/Kconfig -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/Kconfig -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/Kconfig -@@ -425,6 +425,13 @@ config DVB_CXD2820R - help - Say Y when you want to support this frontend. - -+config DVB_RTL2830 -+ tristate "Realtek RTL2830 DVB-T" -+ depends on DVB_CORE && I2C -+ default m if DVB_FE_CUSTOMISE -+ help -+ Say Y when you want to support this frontend. -+ - comment "DVB-C (cable) frontends" - depends on DVB_CORE - -@@ -698,6 +705,19 @@ config DVB_IT913X_FE - A DVB-T tuner module. - Say Y when you want to support this frontend. - -+config DVB_M88RS2000 -+ tristate "M88RS2000 DVB-S demodulator and tuner" -+ depends on DVB_CORE && I2C -+ default m if DVB_FE_CUSTOMISE -+ help -+ A DVB-S tuner module. -+ Say Y when you want to support this frontend. -+ -+config DVB_AF9033 -+ tristate "Afatech AF9033 DVB-T demodulator" -+ depends on DVB_CORE && I2C -+ default m if DVB_FE_CUSTOMISE -+ - comment "Tools to develop new frontends" - - config DVB_DUMMY_FE -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/Makefile -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/Makefile -@@ -2,8 +2,8 @@ - # Makefile for the kernel DVB frontend device drivers. - # - --ccflags-y += -Idrivers/media/dvb/dvb-core/ --ccflags-y += -Idrivers/media/common/tuners/ -+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core/ -+ccflags-y += -I$(srctree)/drivers/media/common/tuners/ - - stb0899-objs = stb0899_drv.o stb0899_algo.o - stv0900-objs = stv0900_core.o stv0900_sw.o -@@ -96,4 +96,7 @@ obj-$(CONFIG_DVB_TDA18271C2DD) += tda182 - obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o - obj-$(CONFIG_DVB_A8293) += a8293.o - obj-$(CONFIG_DVB_TDA10071) += tda10071.o -+obj-$(CONFIG_DVB_RTL2830) += rtl2830.o -+obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o -+obj-$(CONFIG_DVB_AF9033) += af9033.o - -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830.c -@@ -0,0 +1,562 @@ -+/* -+ * Realtek RTL2830 DVB-T demodulator driver -+ * -+ * Copyright (C) 2011 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+ -+/* -+ * Driver implements own I2C-adapter for tuner I2C access. That's since chip -+ * have unusual I2C-gate control which closes gate automatically after each -+ * I2C transfer. Using own I2C adapter we can workaround that. -+ */ -+ -+#include "rtl2830_priv.h" -+ -+int rtl2830_debug; -+module_param_named(debug, rtl2830_debug, int, 0644); -+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -+ -+/* write multiple hardware registers */ -+static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) -+{ -+ int ret; -+ u8 buf[1+len]; -+ struct i2c_msg msg[1] = { -+ { -+ .addr = priv->cfg.i2c_addr, -+ .flags = 0, -+ .len = 1+len, -+ .buf = buf, -+ } -+ }; -+ -+ buf[0] = reg; -+ memcpy(&buf[1], val, len); -+ -+ ret = i2c_transfer(priv->i2c, msg, 1); -+ if (ret == 1) { -+ ret = 0; -+ } else { -+ warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); -+ ret = -EREMOTEIO; -+ } -+ return ret; -+} -+ -+/* read multiple hardware registers */ -+static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) -+{ -+ int ret; -+ struct i2c_msg msg[2] = { -+ { -+ .addr = priv->cfg.i2c_addr, -+ .flags = 0, -+ .len = 1, -+ .buf = ®, -+ }, { -+ .addr = priv->cfg.i2c_addr, -+ .flags = I2C_M_RD, -+ .len = len, -+ .buf = val, -+ } -+ }; -+ -+ ret = i2c_transfer(priv->i2c, msg, 2); -+ if (ret == 2) { -+ ret = 0; -+ } else { -+ warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); -+ ret = -EREMOTEIO; -+ } -+ return ret; -+} -+ -+/* write multiple registers */ -+static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) -+{ -+ int ret; -+ u8 reg2 = (reg >> 0) & 0xff; -+ u8 page = (reg >> 8) & 0xff; -+ -+ /* switch bank if needed */ -+ if (page != priv->page) { -+ ret = rtl2830_wr(priv, 0x00, &page, 1); -+ if (ret) -+ return ret; -+ -+ priv->page = page; -+ } -+ -+ return rtl2830_wr(priv, reg2, val, len); -+} -+ -+/* read multiple registers */ -+static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) -+{ -+ int ret; -+ u8 reg2 = (reg >> 0) & 0xff; -+ u8 page = (reg >> 8) & 0xff; -+ -+ /* switch bank if needed */ -+ if (page != priv->page) { -+ ret = rtl2830_wr(priv, 0x00, &page, 1); -+ if (ret) -+ return ret; -+ -+ priv->page = page; -+ } -+ -+ return rtl2830_rd(priv, reg2, val, len); -+} -+ -+#if 0 /* currently not used */ -+/* write single register */ -+static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val) -+{ -+ return rtl2830_wr_regs(priv, reg, &val, 1); -+} -+#endif -+ -+/* read single register */ -+static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val) -+{ -+ return rtl2830_rd_regs(priv, reg, val, 1); -+} -+ -+/* write single register with mask */ -+int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) -+{ -+ int ret; -+ u8 tmp; -+ -+ /* no need for read if whole reg is written */ -+ if (mask != 0xff) { -+ ret = rtl2830_rd_regs(priv, reg, &tmp, 1); -+ if (ret) -+ return ret; -+ -+ val &= mask; -+ tmp &= ~mask; -+ val |= tmp; -+ } -+ -+ return rtl2830_wr_regs(priv, reg, &val, 1); -+} -+ -+/* read single register with mask */ -+int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask) -+{ -+ int ret, i; -+ u8 tmp; -+ -+ ret = rtl2830_rd_regs(priv, reg, &tmp, 1); -+ if (ret) -+ return ret; -+ -+ tmp &= mask; -+ -+ /* find position of the first bit */ -+ for (i = 0; i < 8; i++) { -+ if ((mask >> i) & 0x01) -+ break; -+ } -+ *val = tmp >> i; -+ -+ return 0; -+} -+ -+static int rtl2830_init(struct dvb_frontend *fe) -+{ -+ struct rtl2830_priv *priv = fe->demodulator_priv; -+ int ret, i; -+ u64 num; -+ u8 buf[3], tmp; -+ u32 if_ctl; -+ struct rtl2830_reg_val_mask tab[] = { -+ { 0x00d, 0x01, 0x03 }, -+ { 0x00d, 0x10, 0x10 }, -+ { 0x104, 0x00, 0x1e }, -+ { 0x105, 0x80, 0x80 }, -+ { 0x110, 0x02, 0x03 }, -+ { 0x110, 0x08, 0x0c }, -+ { 0x17b, 0x00, 0x40 }, -+ { 0x17d, 0x05, 0x0f }, -+ { 0x17d, 0x50, 0xf0 }, -+ { 0x18c, 0x08, 0x0f }, -+ { 0x18d, 0x00, 0xc0 }, -+ { 0x188, 0x05, 0x0f }, -+ { 0x189, 0x00, 0xfc }, -+ { 0x2d5, 0x02, 0x02 }, -+ { 0x2f1, 0x02, 0x06 }, -+ { 0x2f1, 0x20, 0xf8 }, -+ { 0x16d, 0x00, 0x01 }, -+ { 0x1a6, 0x00, 0x80 }, -+ { 0x106, priv->cfg.vtop, 0x3f }, -+ { 0x107, priv->cfg.krf, 0x3f }, -+ { 0x112, 0x28, 0xff }, -+ { 0x103, priv->cfg.agc_targ_val, 0xff }, -+ { 0x00a, 0x02, 0x07 }, -+ { 0x140, 0x0c, 0x3c }, -+ { 0x140, 0x40, 0xc0 }, -+ { 0x15b, 0x05, 0x07 }, -+ { 0x15b, 0x28, 0x38 }, -+ { 0x15c, 0x05, 0x07 }, -+ { 0x15c, 0x28, 0x38 }, -+ { 0x115, priv->cfg.spec_inv, 0x01 }, -+ { 0x16f, 0x01, 0x07 }, -+ { 0x170, 0x18, 0x38 }, -+ { 0x172, 0x0f, 0x0f }, -+ { 0x173, 0x08, 0x38 }, -+ { 0x175, 0x01, 0x07 }, -+ { 0x176, 0x00, 0xc0 }, -+ }; -+ -+ for (i = 0; i < ARRAY_SIZE(tab); i++) { -+ ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val, -+ tab[i].mask); -+ if (ret) -+ goto err; -+ } -+ -+ ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2); -+ if (ret) -+ goto err; -+ -+ ret = rtl2830_wr_regs(priv, 0x195, -+ "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); -+ if (ret) -+ goto err; -+ -+ num = priv->cfg.if_dvbt % priv->cfg.xtal; -+ num *= 0x400000; -+ num = div_u64(num, priv->cfg.xtal); -+ num = -num; -+ if_ctl = num & 0x3fffff; -+ dbg("%s: if_ctl=%08x", __func__, if_ctl); -+ -+ ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */ -+ if (ret) -+ goto err; -+ -+ buf[0] = tmp << 6; -+ buf[0] = (if_ctl >> 16) & 0x3f; -+ buf[1] = (if_ctl >> 8) & 0xff; -+ buf[2] = (if_ctl >> 0) & 0xff; -+ -+ ret = rtl2830_wr_regs(priv, 0x119, buf, 3); -+ if (ret) -+ goto err; -+ -+ /* TODO: spec init */ -+ -+ /* soft reset */ -+ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04); -+ if (ret) -+ goto err; -+ -+ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04); -+ if (ret) -+ goto err; -+ -+ priv->sleeping = false; -+ -+ return ret; -+err: -+ dbg("%s: failed=%d", __func__, ret); -+ return ret; -+} -+ -+static int rtl2830_sleep(struct dvb_frontend *fe) -+{ -+ struct rtl2830_priv *priv = fe->demodulator_priv; -+ priv->sleeping = true; -+ return 0; -+} -+ -+int rtl2830_get_tune_settings(struct dvb_frontend *fe, -+ struct dvb_frontend_tune_settings *s) -+{ -+ s->min_delay_ms = 500; -+ s->step_size = fe->ops.info.frequency_stepsize * 2; -+ s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; -+ -+ return 0; -+} -+ -+static int rtl2830_set_frontend(struct dvb_frontend *fe) -+{ -+ struct rtl2830_priv *priv = fe->demodulator_priv; -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ int ret, i; -+ static u8 bw_params1[3][34] = { -+ { -+ 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41, -+ 0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a, -+ 0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82, -+ 0x03, 0x73, 0x03, 0xcf, /* 6 MHz */ -+ }, { -+ 0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca, -+ 0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca, -+ 0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e, -+ 0x03, 0xd0, 0x04, 0x53, /* 7 MHz */ -+ }, { -+ 0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0, -+ 0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a, -+ 0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f, -+ 0x04, 0x24, 0x04, 0xdb, /* 8 MHz */ -+ }, -+ }; -+ static u8 bw_params2[3][6] = { -+ {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */ -+ {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */ -+ {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */ -+ }; -+ -+ -+ dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__, -+ c->frequency, c->bandwidth_hz, c->inversion); -+ -+ /* program tuner */ -+ if (fe->ops.tuner_ops.set_params) -+ fe->ops.tuner_ops.set_params(fe); -+ -+ switch (c->bandwidth_hz) { -+ case 6000000: -+ i = 0; -+ break; -+ case 7000000: -+ i = 1; -+ break; -+ case 8000000: -+ i = 2; -+ break; -+ default: -+ dbg("invalid bandwidth"); -+ return -EINVAL; -+ } -+ -+ ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06); -+ if (ret) -+ goto err; -+ -+ /* 1/2 split I2C write */ -+ ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17); -+ if (ret) -+ goto err; -+ -+ /* 2/2 split I2C write */ -+ ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17); -+ if (ret) -+ goto err; -+ -+ ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6); -+ if (ret) -+ goto err; -+ -+ return ret; -+err: -+ dbg("%s: failed=%d", __func__, ret); -+ return ret; -+} -+ -+static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) -+{ -+ struct rtl2830_priv *priv = fe->demodulator_priv; -+ int ret; -+ u8 tmp; -+ *status = 0; -+ -+ if (priv->sleeping) -+ return 0; -+ -+ ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */ -+ if (ret) -+ goto err; -+ -+ if (tmp == 11) { -+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | -+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; -+ } else if (tmp == 10) { -+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | -+ FE_HAS_VITERBI; -+ } -+ -+ return ret; -+err: -+ dbg("%s: failed=%d", __func__, ret); -+ return ret; -+} -+ -+static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) -+{ -+ *snr = 0; -+ return 0; -+} -+ -+static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) -+{ -+ *ber = 0; -+ return 0; -+} -+ -+static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -+{ -+ *ucblocks = 0; -+ return 0; -+} -+ -+static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -+{ -+ *strength = 0; -+ return 0; -+} -+ -+static struct dvb_frontend_ops rtl2830_ops; -+ -+static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter) -+{ -+ return I2C_FUNC_I2C; -+} -+ -+static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, -+ struct i2c_msg msg[], int num) -+{ -+ struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap); -+ int ret; -+ -+ /* open i2c-gate */ -+ ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08); -+ if (ret) -+ goto err; -+ -+ ret = i2c_transfer(priv->i2c, msg, num); -+ if (ret < 0) -+ warn("tuner i2c failed=%d", ret); -+ -+ return ret; -+err: -+ dbg("%s: failed=%d", __func__, ret); -+ return ret; -+} -+ -+static struct i2c_algorithm rtl2830_tuner_i2c_algo = { -+ .master_xfer = rtl2830_tuner_i2c_xfer, -+ .functionality = rtl2830_tuner_i2c_func, -+}; -+ -+struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe) -+{ -+ struct rtl2830_priv *priv = fe->demodulator_priv; -+ return &priv->tuner_i2c_adapter; -+} -+EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter); -+ -+static void rtl2830_release(struct dvb_frontend *fe) -+{ -+ struct rtl2830_priv *priv = fe->demodulator_priv; -+ -+ i2c_del_adapter(&priv->tuner_i2c_adapter); -+ kfree(priv); -+} -+ -+struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg, -+ struct i2c_adapter *i2c) -+{ -+ struct rtl2830_priv *priv = NULL; -+ int ret = 0; -+ u8 tmp; -+ -+ /* allocate memory for the internal state */ -+ priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL); -+ if (priv == NULL) -+ goto err; -+ -+ /* setup the priv */ -+ priv->i2c = i2c; -+ memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config)); -+ -+ /* check if the demod is there */ -+ ret = rtl2830_rd_reg(priv, 0x000, &tmp); -+ if (ret) -+ goto err; -+ -+ /* create dvb_frontend */ -+ memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops)); -+ priv->fe.demodulator_priv = priv; -+ -+ /* create tuner i2c adapter */ -+ strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter", -+ sizeof(priv->tuner_i2c_adapter.name)); -+ priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo; -+ priv->tuner_i2c_adapter.algo_data = NULL; -+ i2c_set_adapdata(&priv->tuner_i2c_adapter, priv); -+ if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) { -+ err("tuner I2C bus could not be initialized"); -+ goto err; -+ } -+ -+ priv->sleeping = true; -+ -+ return &priv->fe; -+err: -+ dbg("%s: failed=%d", __func__, ret); -+ kfree(priv); -+ return NULL; -+} -+EXPORT_SYMBOL(rtl2830_attach); -+ -+static struct dvb_frontend_ops rtl2830_ops = { -+ .delsys = { SYS_DVBT }, -+ .info = { -+ .name = "Realtek RTL2830 (DVB-T)", -+ .caps = FE_CAN_FEC_1_2 | -+ FE_CAN_FEC_2_3 | -+ FE_CAN_FEC_3_4 | -+ FE_CAN_FEC_5_6 | -+ FE_CAN_FEC_7_8 | -+ FE_CAN_FEC_AUTO | -+ FE_CAN_QPSK | -+ FE_CAN_QAM_16 | -+ FE_CAN_QAM_64 | -+ FE_CAN_QAM_AUTO | -+ FE_CAN_TRANSMISSION_MODE_AUTO | -+ FE_CAN_GUARD_INTERVAL_AUTO | -+ FE_CAN_HIERARCHY_AUTO | -+ FE_CAN_RECOVER | -+ FE_CAN_MUTE_TS -+ }, -+ -+ .release = rtl2830_release, -+ -+ .init = rtl2830_init, -+ .sleep = rtl2830_sleep, -+ -+ .get_tune_settings = rtl2830_get_tune_settings, -+ -+ .set_frontend = rtl2830_set_frontend, -+ -+ .read_status = rtl2830_read_status, -+ .read_snr = rtl2830_read_snr, -+ .read_ber = rtl2830_read_ber, -+ .read_ucblocks = rtl2830_read_ucblocks, -+ .read_signal_strength = rtl2830_read_signal_strength, -+}; -+ -+MODULE_AUTHOR("Antti Palosaari "); -+MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver"); -+MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830.h -@@ -0,0 +1,97 @@ -+/* -+ * Realtek RTL2830 DVB-T demodulator driver -+ * -+ * Copyright (C) 2011 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#ifndef RTL2830_H -+#define RTL2830_H -+ -+#include -+ -+struct rtl2830_config { -+ /* -+ * Demodulator I2C address. -+ */ -+ u8 i2c_addr; -+ -+ /* -+ * Xtal frequency. -+ * Hz -+ * 4000000, 16000000, 25000000, 28800000 -+ */ -+ u32 xtal; -+ -+ /* -+ * TS output mode. -+ */ -+ u8 ts_mode; -+ -+ /* -+ * Spectrum inversion. -+ */ -+ bool spec_inv; -+ -+ /* -+ * IFs for all used modes. -+ * Hz -+ * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000 -+ */ -+ u32 if_dvbt; -+ -+ /* -+ */ -+ u8 vtop; -+ -+ /* -+ */ -+ u8 krf; -+ -+ /* -+ */ -+ u8 agc_targ_val; -+}; -+ -+#if defined(CONFIG_DVB_RTL2830) || \ -+ (defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE)) -+extern struct dvb_frontend *rtl2830_attach( -+ const struct rtl2830_config *config, -+ struct i2c_adapter *i2c -+); -+ -+extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( -+ struct dvb_frontend *fe -+); -+#else -+static inline struct dvb_frontend *rtl2830_attach( -+ const struct rtl2830_config *config, -+ struct i2c_adapter *i2c -+) -+{ -+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -+ return NULL; -+} -+ -+static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( -+ struct dvb_frontend *fe -+) -+{ -+ return NULL; -+} -+#endif -+ -+#endif /* RTL2830_H */ -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830_priv.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/rtl2830_priv.h -@@ -0,0 +1,57 @@ -+/* -+ * Realtek RTL2830 DVB-T demodulator driver -+ * -+ * Copyright (C) 2011 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#ifndef RTL2830_PRIV_H -+#define RTL2830_PRIV_H -+ -+#include "dvb_frontend.h" -+#include "rtl2830.h" -+ -+#define LOG_PREFIX "rtl2830" -+ -+#undef dbg -+#define dbg(f, arg...) \ -+ if (rtl2830_debug) \ -+ printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -+#undef err -+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -+#undef info -+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -+#undef warn -+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) -+ -+struct rtl2830_priv { -+ struct i2c_adapter *i2c; -+ struct dvb_frontend fe; -+ struct rtl2830_config cfg; -+ struct i2c_adapter tuner_i2c_adapter; -+ -+ bool sleeping; -+ -+ u8 page; /* active register page */ -+}; -+ -+struct rtl2830_reg_val_mask { -+ u16 reg; -+ u8 val; -+ u8 mask; -+}; -+ -+#endif /* RTL2830_PRIV_H */ -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/rtl28xxu.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/rtl28xxu.c -@@ -0,0 +1,982 @@ -+/* -+ * Realtek RTL28xxU DVB USB driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * Copyright (C) 2011 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#include "rtl28xxu.h" -+ -+#include "rtl2830.h" -+ -+#include "qt1010.h" -+#include "mt2060.h" -+#include "mxl5005s.h" -+ -+/* debug */ -+static int dvb_usb_rtl28xxu_debug; -+module_param_named(debug, dvb_usb_rtl28xxu_debug, int, 0644); -+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -+ -+static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) -+{ -+ int ret; -+ unsigned int pipe; -+ u8 requesttype; -+ u8 *buf; -+ -+ buf = kmalloc(req->size, GFP_KERNEL); -+ if (!buf) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ if (req->index & CMD_WR_FLAG) { -+ /* write */ -+ memcpy(buf, req->data, req->size); -+ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); -+ pipe = usb_sndctrlpipe(d->udev, 0); -+ } else { -+ /* read */ -+ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); -+ pipe = usb_rcvctrlpipe(d->udev, 0); -+ } -+ -+ ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value, -+ req->index, buf, req->size, 1000); -+ if (ret > 0) -+ ret = 0; -+ -+ deb_dump(0, requesttype, req->value, req->index, buf, req->size, -+ deb_xfer); -+ -+ /* read request, copy returned data to return buf */ -+ if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) -+ memcpy(req->data, buf, req->size); -+ -+ kfree(buf); -+ -+ if (ret) -+ goto err; -+ -+ return ret; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) -+{ -+ struct rtl28xxu_req req; -+ -+ if (reg < 0x3000) -+ req.index = CMD_USB_WR; -+ else if (reg < 0x4000) -+ req.index = CMD_SYS_WR; -+ else -+ req.index = CMD_IR_WR; -+ -+ req.value = reg; -+ req.size = len; -+ req.data = val; -+ -+ return rtl28xxu_ctrl_msg(d, &req); -+} -+ -+static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) -+{ -+ struct rtl28xxu_req req; -+ -+ if (reg < 0x3000) -+ req.index = CMD_USB_RD; -+ else if (reg < 0x4000) -+ req.index = CMD_SYS_RD; -+ else -+ req.index = CMD_IR_RD; -+ -+ req.value = reg; -+ req.size = len; -+ req.data = val; -+ -+ return rtl28xxu_ctrl_msg(d, &req); -+} -+ -+static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) -+{ -+ return rtl2831_wr_regs(d, reg, &val, 1); -+} -+ -+static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) -+{ -+ return rtl2831_rd_regs(d, reg, val, 1); -+} -+ -+/* I2C */ -+static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], -+ int num) -+{ -+ int ret; -+ struct dvb_usb_device *d = i2c_get_adapdata(adap); -+ struct rtl28xxu_priv *priv = d->priv; -+ struct rtl28xxu_req req; -+ -+ /* -+ * It is not known which are real I2C bus xfer limits, but testing -+ * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes. -+ * TODO: find out RTL2832U lens -+ */ -+ -+ /* -+ * I2C adapter logic looks rather complicated due to fact it handles -+ * three different access methods. Those methods are; -+ * 1) integrated demod access -+ * 2) old I2C access -+ * 3) new I2C access -+ * -+ * Used method is selected in order 1, 2, 3. Method 3 can handle all -+ * requests but there is two reasons why not use it always; -+ * 1) It is most expensive, usually two USB messages are needed -+ * 2) At least RTL2831U does not support it -+ * -+ * Method 3 is needed in case of I2C write+read (typical register read) -+ * where write is more than one byte. -+ */ -+ -+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0) -+ return -EAGAIN; -+ -+ if (num == 2 && !(msg[0].flags & I2C_M_RD) && -+ (msg[1].flags & I2C_M_RD)) { -+ if (msg[0].len > 24 || msg[1].len > 24) { -+ /* TODO: check msg[0].len max */ -+ ret = -EOPNOTSUPP; -+ goto err_mutex_unlock; -+ } else if (msg[0].addr == 0x10) { -+ /* method 1 - integrated demod */ -+ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); -+ req.index = CMD_DEMOD_RD | priv->page; -+ req.size = msg[1].len; -+ req.data = &msg[1].buf[0]; -+ ret = rtl28xxu_ctrl_msg(d, &req); -+ } else if (msg[0].len < 2) { -+ /* method 2 - old I2C */ -+ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); -+ req.index = CMD_I2C_RD; -+ req.size = msg[1].len; -+ req.data = &msg[1].buf[0]; -+ ret = rtl28xxu_ctrl_msg(d, &req); -+ } else { -+ /* method 3 - new I2C */ -+ req.value = (msg[0].addr << 1); -+ req.index = CMD_I2C_DA_WR; -+ req.size = msg[0].len; -+ req.data = msg[0].buf; -+ ret = rtl28xxu_ctrl_msg(d, &req); -+ if (ret) -+ goto err_mutex_unlock; -+ -+ req.value = (msg[0].addr << 1); -+ req.index = CMD_I2C_DA_RD; -+ req.size = msg[1].len; -+ req.data = msg[1].buf; -+ ret = rtl28xxu_ctrl_msg(d, &req); -+ } -+ } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { -+ if (msg[0].len > 22) { -+ /* TODO: check msg[0].len max */ -+ ret = -EOPNOTSUPP; -+ goto err_mutex_unlock; -+ } else if (msg[0].addr == 0x10) { -+ /* method 1 - integrated demod */ -+ if (msg[0].buf[0] == 0x00) { -+ /* save demod page for later demod access */ -+ priv->page = msg[0].buf[1]; -+ ret = 0; -+ } else { -+ req.value = (msg[0].buf[0] << 8) | -+ (msg[0].addr << 1); -+ req.index = CMD_DEMOD_WR | priv->page; -+ req.size = msg[0].len-1; -+ req.data = &msg[0].buf[1]; -+ ret = rtl28xxu_ctrl_msg(d, &req); -+ } -+ } else if (msg[0].len < 23) { -+ /* method 2 - old I2C */ -+ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); -+ req.index = CMD_I2C_WR; -+ req.size = msg[0].len-1; -+ req.data = &msg[0].buf[1]; -+ ret = rtl28xxu_ctrl_msg(d, &req); -+ } else { -+ /* method 3 - new I2C */ -+ req.value = (msg[0].addr << 1); -+ req.index = CMD_I2C_DA_WR; -+ req.size = msg[0].len; -+ req.data = msg[0].buf; -+ ret = rtl28xxu_ctrl_msg(d, &req); -+ } -+ } else { -+ ret = -EINVAL; -+ } -+ -+err_mutex_unlock: -+ mutex_unlock(&d->i2c_mutex); -+ -+ return ret ? ret : num; -+} -+ -+static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter) -+{ -+ return I2C_FUNC_I2C; -+} -+ -+static struct i2c_algorithm rtl28xxu_i2c_algo = { -+ .master_xfer = rtl28xxu_i2c_xfer, -+ .functionality = rtl28xxu_i2c_func, -+}; -+ -+static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { -+ .i2c_addr = 0x10, /* 0x20 */ -+ .xtal = 28800000, -+ .ts_mode = 0, -+ .spec_inv = 1, -+ .if_dvbt = 36150000, -+ .vtop = 0x20, -+ .krf = 0x04, -+ .agc_targ_val = 0x2d, -+ -+}; -+ -+static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { -+ .i2c_addr = 0x10, /* 0x20 */ -+ .xtal = 28800000, -+ .ts_mode = 0, -+ .spec_inv = 1, -+ .if_dvbt = 36125000, -+ .vtop = 0x20, -+ .krf = 0x04, -+ .agc_targ_val = 0x2d, -+}; -+ -+static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { -+ .i2c_addr = 0x10, /* 0x20 */ -+ .xtal = 28800000, -+ .ts_mode = 0, -+ .spec_inv = 0, -+ .if_dvbt = 4570000, -+ .vtop = 0x3f, -+ .krf = 0x04, -+ .agc_targ_val = 0x3e, -+}; -+ -+static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) -+{ -+ int ret; -+ struct rtl28xxu_priv *priv = adap->dev->priv; -+ u8 buf[1]; -+ struct rtl2830_config *rtl2830_config; -+ /* open RTL2831U/RTL2830 I2C gate */ -+ struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" }; -+ /* for MT2060 tuner probe */ -+ struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf }; -+ /* for QT1010 tuner probe */ -+ struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf }; -+ -+ deb_info("%s:\n", __func__); -+ -+ /* -+ * RTL2831U GPIOs -+ * ========================================================= -+ * GPIO0 | tuner#0 | 0 off | 1 on | MXL5005S (?) -+ * GPIO2 | LED | 0 off | 1 on | -+ * GPIO4 | tuner#1 | 0 on | 1 off | MT2060 -+ */ -+ -+ /* GPIO direction */ -+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); -+ if (ret) -+ goto err; -+ -+ /* enable as output GPIO0, GPIO2, GPIO4 */ -+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); -+ if (ret) -+ goto err; -+ -+ /* -+ * Probe used tuner. We need to know used tuner before demod attach -+ * since there is some demod params needed to set according to tuner. -+ */ -+ -+ /* open demod I2C gate */ -+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate); -+ if (ret) -+ goto err; -+ -+ /* check QT1010 ID(?) register; reg=0f val=2c */ -+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010); -+ if (ret == 0 && buf[0] == 0x2c) { -+ priv->tuner = TUNER_RTL2830_QT1010; -+ rtl2830_config = &rtl28xxu_rtl2830_qt1010_config; -+ deb_info("%s: QT1010\n", __func__); -+ goto found; -+ } else { -+ deb_info("%s: QT1010 probe failed=%d - %02x\n", -+ __func__, ret, buf[0]); -+ } -+ -+ /* open demod I2C gate */ -+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate); -+ if (ret) -+ goto err; -+ -+ /* check MT2060 ID register; reg=00 val=63 */ -+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060); -+ if (ret == 0 && buf[0] == 0x63) { -+ priv->tuner = TUNER_RTL2830_MT2060; -+ rtl2830_config = &rtl28xxu_rtl2830_mt2060_config; -+ deb_info("%s: MT2060\n", __func__); -+ goto found; -+ } else { -+ deb_info("%s: MT2060 probe failed=%d - %02x\n", -+ __func__, ret, buf[0]); -+ } -+ -+ /* assume MXL5005S */ -+ ret = 0; -+ priv->tuner = TUNER_RTL2830_MXL5005S; -+ rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config; -+ deb_info("%s: MXL5005S\n", __func__); -+ goto found; -+ -+found: -+ /* attach demodulator */ -+ adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config, -+ &adap->dev->i2c_adap); -+ if (adap->fe_adap[0].fe == NULL) { -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ return ret; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) -+{ -+ int ret; -+ struct rtl28xxu_priv *priv = adap->dev->priv; -+ u8 buf[1]; -+ /* open RTL2832U/RTL2832 I2C gate */ -+ struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"}; -+ /* close RTL2832U/RTL2832 I2C gate */ -+ struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"}; -+ /* for FC2580 tuner probe */ -+ struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf}; -+ -+ deb_info("%s:\n", __func__); -+ -+ /* GPIO direction */ -+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); -+ if (ret) -+ goto err; -+ -+ /* enable as output GPIO0, GPIO2, GPIO4 */ -+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); -+ if (ret) -+ goto err; -+ -+ ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8); -+ if (ret) -+ goto err; -+ -+ /* -+ * Probe used tuner. We need to know used tuner before demod attach -+ * since there is some demod params needed to set according to tuner. -+ */ -+ -+ /* open demod I2C gate */ -+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open); -+ if (ret) -+ goto err; -+ -+ /* check FC2580 ID register; reg=01 val=56 */ -+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580); -+ if (ret == 0 && buf[0] == 0x56) { -+ priv->tuner = TUNER_RTL2832_FC2580; -+ deb_info("%s: FC2580\n", __func__); -+ goto found; -+ } else { -+ deb_info("%s: FC2580 probe failed=%d - %02x\n", -+ __func__, ret, buf[0]); -+ } -+ -+ /* close demod I2C gate */ -+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close); -+ if (ret) -+ goto err; -+ -+ /* tuner not found */ -+ ret = -ENODEV; -+ goto err; -+ -+found: -+ /* close demod I2C gate */ -+ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close); -+ if (ret) -+ goto err; -+ -+ /* attach demodulator */ -+ /* TODO: */ -+ -+ return ret; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static struct qt1010_config rtl28xxu_qt1010_config = { -+ .i2c_address = 0x62, /* 0xc4 */ -+}; -+ -+static struct mt2060_config rtl28xxu_mt2060_config = { -+ .i2c_address = 0x60, /* 0xc0 */ -+ .clock_out = 0, -+}; -+ -+static struct mxl5005s_config rtl28xxu_mxl5005s_config = { -+ .i2c_address = 0x63, /* 0xc6 */ -+ .if_freq = IF_FREQ_4570000HZ, -+ .xtal_freq = CRYSTAL_FREQ_16000000HZ, -+ .agc_mode = MXL_SINGLE_AGC, -+ .tracking_filter = MXL_TF_C_H, -+ .rssi_enable = MXL_RSSI_ENABLE, -+ .cap_select = MXL_CAP_SEL_ENABLE, -+ .div_out = MXL_DIV_OUT_4, -+ .clock_out = MXL_CLOCK_OUT_DISABLE, -+ .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, -+ .top = MXL5005S_TOP_25P2, -+ .mod_mode = MXL_DIGITAL_MODE, -+ .if_mode = MXL_ZERO_IF, -+ .AgcMasterByte = 0x00, -+}; -+ -+static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) -+{ -+ int ret; -+ struct rtl28xxu_priv *priv = adap->dev->priv; -+ struct i2c_adapter *rtl2830_tuner_i2c; -+ struct dvb_frontend *fe; -+ -+ deb_info("%s:\n", __func__); -+ -+ /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */ -+ rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe); -+ -+ switch (priv->tuner) { -+ case TUNER_RTL2830_QT1010: -+ fe = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, -+ rtl2830_tuner_i2c, &rtl28xxu_qt1010_config); -+ break; -+ case TUNER_RTL2830_MT2060: -+ fe = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, -+ rtl2830_tuner_i2c, &rtl28xxu_mt2060_config, -+ 1220); -+ break; -+ case TUNER_RTL2830_MXL5005S: -+ fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, -+ rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config); -+ break; -+ default: -+ fe = NULL; -+ err("unknown tuner=%d", priv->tuner); -+ } -+ -+ if (fe == NULL) { -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ return 0; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) -+{ -+ int ret; -+ struct rtl28xxu_priv *priv = adap->dev->priv; -+ struct dvb_frontend *fe; -+ -+ deb_info("%s:\n", __func__); -+ -+ switch (priv->tuner) { -+ case TUNER_RTL2832_FC2580: -+ /* TODO: */ -+ fe = NULL; -+ break; -+ default: -+ fe = NULL; -+ err("unknown tuner=%d", priv->tuner); -+ } -+ -+ if (fe == NULL) { -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ return 0; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff) -+{ -+ int ret; -+ u8 buf[2], gpio; -+ -+ deb_info("%s: onoff=%d\n", __func__, onoff); -+ -+ ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio); -+ if (ret) -+ goto err; -+ -+ if (onoff) { -+ buf[0] = 0x00; -+ buf[1] = 0x00; -+ gpio |= 0x04; /* LED on */ -+ } else { -+ buf[0] = 0x10; /* stall EPA */ -+ buf[1] = 0x02; /* reset EPA */ -+ gpio &= (~0x04); /* LED off */ -+ } -+ -+ ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio); -+ if (ret) -+ goto err; -+ -+ ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2); -+ if (ret) -+ goto err; -+ -+ return ret; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff) -+{ -+ int ret; -+ u8 gpio, sys0; -+ -+ deb_info("%s: onoff=%d\n", __func__, onoff); -+ -+ /* demod adc */ -+ ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0); -+ if (ret) -+ goto err; -+ -+ /* tuner power, read GPIOs */ -+ ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); -+ if (ret) -+ goto err; -+ -+ deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio); -+ -+ if (onoff) { -+ gpio |= 0x01; /* GPIO0 = 1 */ -+ gpio &= (~0x10); /* GPIO4 = 0 */ -+ sys0 = sys0 & 0x0f; -+ sys0 |= 0xe0; -+ } else { -+ gpio &= (~0x01); /* GPIO0 = 0 */ -+ gpio |= 0x10; /* GPIO4 = 1 */ -+ sys0 = sys0 & (~0xc0); -+ } -+ -+ deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio); -+ -+ /* demod adc */ -+ ret = rtl2831_wr_reg(d, SYS_SYS0, sys0); -+ if (ret) -+ goto err; -+ -+ /* tuner power, write GPIOs */ -+ ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); -+ if (ret) -+ goto err; -+ -+ return ret; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static int rtl2831u_rc_query(struct dvb_usb_device *d) -+{ -+ int ret, i; -+ struct rtl28xxu_priv *priv = d->priv; -+ u8 buf[5]; -+ u32 rc_code; -+ struct rtl28xxu_reg_val rc_nec_tab[] = { -+ { 0x3033, 0x80 }, -+ { 0x3020, 0x43 }, -+ { 0x3021, 0x16 }, -+ { 0x3022, 0x16 }, -+ { 0x3023, 0x5a }, -+ { 0x3024, 0x2d }, -+ { 0x3025, 0x16 }, -+ { 0x3026, 0x01 }, -+ { 0x3028, 0xb0 }, -+ { 0x3029, 0x04 }, -+ { 0x302c, 0x88 }, -+ { 0x302e, 0x13 }, -+ { 0x3030, 0xdf }, -+ { 0x3031, 0x05 }, -+ }; -+ -+ /* init remote controller */ -+ if (!priv->rc_active) { -+ for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { -+ ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, -+ rc_nec_tab[i].val); -+ if (ret) -+ goto err; -+ } -+ priv->rc_active = true; -+ } -+ -+ ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5); -+ if (ret) -+ goto err; -+ -+ if (buf[4] & 0x01) { -+ if (buf[2] == (u8) ~buf[3]) { -+ if (buf[0] == (u8) ~buf[1]) { -+ /* NEC standard (16 bit) */ -+ rc_code = buf[0] << 8 | buf[2]; -+ } else { -+ /* NEC extended (24 bit) */ -+ rc_code = buf[0] << 16 | -+ buf[1] << 8 | buf[2]; -+ } -+ } else { -+ /* NEC full (32 bit) */ -+ rc_code = buf[0] << 24 | buf[1] << 16 | -+ buf[2] << 8 | buf[3]; -+ } -+ -+ rc_keydown(d->rc_dev, rc_code, 0); -+ -+ ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1); -+ if (ret) -+ goto err; -+ -+ /* repeated intentionally to avoid extra keypress */ -+ ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1); -+ if (ret) -+ goto err; -+ } -+ -+ return ret; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static int rtl2832u_rc_query(struct dvb_usb_device *d) -+{ -+ int ret, i; -+ struct rtl28xxu_priv *priv = d->priv; -+ u8 buf[128]; -+ int len; -+ struct rtl28xxu_reg_val rc_nec_tab[] = { -+ { IR_RX_CTRL, 0x20 }, -+ { IR_RX_BUF_CTRL, 0x80 }, -+ { IR_RX_IF, 0xff }, -+ { IR_RX_IE, 0xff }, -+ { IR_MAX_DURATION0, 0xd0 }, -+ { IR_MAX_DURATION1, 0x07 }, -+ { IR_IDLE_LEN0, 0xc0 }, -+ { IR_IDLE_LEN1, 0x00 }, -+ { IR_GLITCH_LEN, 0x03 }, -+ { IR_RX_CLK, 0x09 }, -+ { IR_RX_CFG, 0x1c }, -+ { IR_MAX_H_TOL_LEN, 0x1e }, -+ { IR_MAX_L_TOL_LEN, 0x1e }, -+ { IR_RX_CTRL, 0x80 }, -+ }; -+ -+ /* init remote controller */ -+ if (!priv->rc_active) { -+ for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { -+ ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, -+ rc_nec_tab[i].val); -+ if (ret) -+ goto err; -+ } -+ priv->rc_active = true; -+ } -+ -+ ret = rtl2831_rd_reg(d, IR_RX_IF, &buf[0]); -+ if (ret) -+ goto err; -+ -+ if (buf[0] != 0x83) -+ goto exit; -+ -+ ret = rtl2831_rd_reg(d, IR_RX_BC, &buf[0]); -+ if (ret) -+ goto err; -+ -+ len = buf[0]; -+ ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len); -+ -+ /* TODO: pass raw IR to Kernel IR decoder */ -+ -+ ret = rtl2831_wr_reg(d, IR_RX_IF, 0x03); -+ ret = rtl2831_wr_reg(d, IR_RX_BUF_CTRL, 0x80); -+ ret = rtl2831_wr_reg(d, IR_RX_CTRL, 0x80); -+ -+exit: -+ return ret; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+enum rtl28xxu_usb_table_entry { -+ RTL2831U_0BDA_2831, -+ RTL2831U_14AA_0160, -+ RTL2831U_14AA_0161, -+}; -+ -+static struct usb_device_id rtl28xxu_table[] = { -+ /* RTL2831U */ -+ [RTL2831U_0BDA_2831] = { -+ USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U)}, -+ [RTL2831U_14AA_0160] = { -+ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT)}, -+ [RTL2831U_14AA_0161] = { -+ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)}, -+ -+ /* RTL2832U */ -+ {} /* terminating entry */ -+}; -+ -+MODULE_DEVICE_TABLE(usb, rtl28xxu_table); -+ -+static struct dvb_usb_device_properties rtl28xxu_properties[] = { -+ { -+ .caps = DVB_USB_IS_AN_I2C_ADAPTER, -+ -+ .usb_ctrl = DEVICE_SPECIFIC, -+ .no_reconnect = 1, -+ -+ .size_of_priv = sizeof(struct rtl28xxu_priv), -+ -+ .num_adapters = 1, -+ .adapter = { -+ { -+ .num_frontends = 1, -+ .fe = { -+ { -+ .frontend_attach = rtl2831u_frontend_attach, -+ .tuner_attach = rtl2831u_tuner_attach, -+ .streaming_ctrl = rtl28xxu_streaming_ctrl, -+ .stream = { -+ .type = USB_BULK, -+ .count = 6, -+ .endpoint = 0x81, -+ .u = { -+ .bulk = { -+ .buffersize = 8*512, -+ } -+ } -+ } -+ } -+ } -+ } -+ }, -+ -+ .power_ctrl = rtl28xxu_power_ctrl, -+ -+ .rc.core = { -+ .protocol = RC_TYPE_NEC, -+ .module_name = "rtl28xxu", -+ .rc_query = rtl2831u_rc_query, -+ .rc_interval = 400, -+ .allowed_protos = RC_TYPE_NEC, -+ .rc_codes = RC_MAP_EMPTY, -+ }, -+ -+ .i2c_algo = &rtl28xxu_i2c_algo, -+ -+ .num_device_descs = 2, -+ .devices = { -+ { -+ .name = "Realtek RTL2831U reference design", -+ .warm_ids = { -+ &rtl28xxu_table[RTL2831U_0BDA_2831], -+ }, -+ }, -+ { -+ .name = "Freecom USB2.0 DVB-T", -+ .warm_ids = { -+ &rtl28xxu_table[RTL2831U_14AA_0160], -+ &rtl28xxu_table[RTL2831U_14AA_0161], -+ }, -+ }, -+ } -+ }, -+ { -+ .caps = DVB_USB_IS_AN_I2C_ADAPTER, -+ -+ .usb_ctrl = DEVICE_SPECIFIC, -+ .no_reconnect = 1, -+ -+ .size_of_priv = sizeof(struct rtl28xxu_priv), -+ -+ .num_adapters = 1, -+ .adapter = { -+ { -+ .num_frontends = 1, -+ .fe = { -+ { -+ .frontend_attach = rtl2832u_frontend_attach, -+ .tuner_attach = rtl2832u_tuner_attach, -+ .streaming_ctrl = rtl28xxu_streaming_ctrl, -+ .stream = { -+ .type = USB_BULK, -+ .count = 6, -+ .endpoint = 0x81, -+ .u = { -+ .bulk = { -+ .buffersize = 8*512, -+ } -+ } -+ } -+ } -+ } -+ } -+ }, -+ -+ .power_ctrl = rtl28xxu_power_ctrl, -+ -+ .rc.core = { -+ .protocol = RC_TYPE_NEC, -+ .module_name = "rtl28xxu", -+ .rc_query = rtl2832u_rc_query, -+ .rc_interval = 400, -+ .allowed_protos = RC_TYPE_NEC, -+ .rc_codes = RC_MAP_EMPTY, -+ }, -+ -+ .i2c_algo = &rtl28xxu_i2c_algo, -+ -+ .num_device_descs = 0, /* disabled as no support for RTL2832 */ -+ .devices = { -+ { -+ .name = "Realtek RTL2832U reference design", -+ }, -+ } -+ }, -+ -+}; -+ -+static int rtl28xxu_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ int ret, i; -+ int properties_count = ARRAY_SIZE(rtl28xxu_properties); -+ struct dvb_usb_device *d; -+ -+ deb_info("%s: interface=%d\n", __func__, -+ intf->cur_altsetting->desc.bInterfaceNumber); -+ -+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0) -+ return 0; -+ -+ for (i = 0; i < properties_count; i++) { -+ ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i], -+ THIS_MODULE, &d, adapter_nr); -+ if (ret == 0 || ret != -ENODEV) -+ break; -+ } -+ -+ if (ret) -+ goto err; -+ -+ /* init USB endpoints */ -+ ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09); -+ if (ret) -+ goto err; -+ -+ ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); -+ if (ret) -+ goto err; -+ -+ ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); -+ if (ret) -+ goto err; -+ -+ return ret; -+err: -+ deb_info("%s: failed=%d\n", __func__, ret); -+ return ret; -+} -+ -+static struct usb_driver rtl28xxu_driver = { -+ .name = "dvb_usb_rtl28xxu", -+ .probe = rtl28xxu_probe, -+ .disconnect = dvb_usb_device_exit, -+ .id_table = rtl28xxu_table, -+}; -+ -+/* module stuff */ -+static int __init rtl28xxu_module_init(void) -+{ -+ int ret; -+ -+ deb_info("%s:\n", __func__); -+ -+ ret = usb_register(&rtl28xxu_driver); -+ if (ret) -+ err("usb_register failed=%d", ret); -+ -+ return ret; -+} -+ -+static void __exit rtl28xxu_module_exit(void) -+{ -+ deb_info("%s:\n", __func__); -+ -+ /* deregister this driver from the USB subsystem */ -+ usb_deregister(&rtl28xxu_driver); -+} -+ -+module_init(rtl28xxu_module_init); -+module_exit(rtl28xxu_module_exit); -+ -+MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver"); -+MODULE_AUTHOR("Antti Palosaari "); -+MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/rtl28xxu.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/rtl28xxu.h -@@ -0,0 +1,264 @@ -+/* -+ * Realtek RTL28xxU DVB USB driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * Copyright (C) 2011 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#ifndef RTL28XXU_H -+#define RTL28XXU_H -+ -+#define DVB_USB_LOG_PREFIX "rtl28xxu" -+#include "dvb-usb.h" -+ -+#define deb_info(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x01, args) -+#define deb_rc(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x02, args) -+#define deb_xfer(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x04, args) -+#define deb_reg(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x08, args) -+#define deb_i2c(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x10, args) -+#define deb_fw(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x20, args) -+ -+#define deb_dump(r, t, v, i, b, l, func) { \ -+ int loop_; \ -+ func("%02x %02x %02x %02x %02x %02x %02x %02x", \ -+ t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ -+ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ -+ func(" >>> "); \ -+ else \ -+ func(" <<< "); \ -+ for (loop_ = 0; loop_ < l; loop_++) \ -+ func("%02x ", b[loop_]); \ -+ func("\n");\ -+} -+ -+/* -+ * USB commands -+ * (usb_control_msg() index parameter) -+ */ -+ -+#define DEMOD 0x0000 -+#define USB 0x0100 -+#define SYS 0x0200 -+#define I2C 0x0300 -+#define I2C_DA 0x0600 -+ -+#define CMD_WR_FLAG 0x0010 -+#define CMD_DEMOD_RD 0x0000 -+#define CMD_DEMOD_WR 0x0010 -+#define CMD_USB_RD 0x0100 -+#define CMD_USB_WR 0x0110 -+#define CMD_SYS_RD 0x0200 -+#define CMD_IR_RD 0x0201 -+#define CMD_IR_WR 0x0211 -+#define CMD_SYS_WR 0x0210 -+#define CMD_I2C_RD 0x0300 -+#define CMD_I2C_WR 0x0310 -+#define CMD_I2C_DA_RD 0x0600 -+#define CMD_I2C_DA_WR 0x0610 -+ -+ -+struct rtl28xxu_priv { -+ u8 chip_id; -+ u8 tuner; -+ u8 page; /* integrated demod active register page */ -+ bool rc_active; -+}; -+ -+enum rtl28xxu_chip_id { -+ CHIP_ID_NONE, -+ CHIP_ID_RTL2831U, -+ CHIP_ID_RTL2832U, -+}; -+ -+enum rtl28xxu_tuner { -+ TUNER_NONE, -+ -+ TUNER_RTL2830_QT1010, -+ TUNER_RTL2830_MT2060, -+ TUNER_RTL2830_MXL5005S, -+ -+ TUNER_RTL2832_MT2266, -+ TUNER_RTL2832_FC2580, -+ TUNER_RTL2832_MT2063, -+ TUNER_RTL2832_MAX3543, -+ TUNER_RTL2832_TUA9001, -+ TUNER_RTL2832_MXL5007T, -+ TUNER_RTL2832_FC0012, -+ TUNER_RTL2832_E4000, -+ TUNER_RTL2832_TDA18272, -+ TUNER_RTL2832_FC0013, -+}; -+ -+struct rtl28xxu_req { -+ u16 value; -+ u16 index; -+ u16 size; -+ u8 *data; -+}; -+ -+struct rtl28xxu_reg_val { -+ u16 reg; -+ u8 val; -+}; -+ -+/* -+ * memory map -+ * -+ * 0x0000 DEMOD : demodulator -+ * 0x2000 USB : SIE, USB endpoint, debug, DMA -+ * 0x3000 SYS : system -+ * 0xfc00 RC : remote controller (not RTL2831U) -+ */ -+ -+/* -+ * USB registers -+ */ -+/* SIE Control Registers */ -+#define USB_SYSCTL 0x2000 /* USB system control */ -+#define USB_SYSCTL_0 0x2000 /* USB system control */ -+#define USB_SYSCTL_1 0x2001 /* USB system control */ -+#define USB_SYSCTL_2 0x2002 /* USB system control */ -+#define USB_SYSCTL_3 0x2003 /* USB system control */ -+#define USB_IRQSTAT 0x2008 /* SIE interrupt status */ -+#define USB_IRQEN 0x200C /* SIE interrupt enable */ -+#define USB_CTRL 0x2010 /* USB control */ -+#define USB_STAT 0x2014 /* USB status */ -+#define USB_DEVADDR 0x2018 /* USB device address */ -+#define USB_TEST 0x201C /* USB test mode */ -+#define USB_FRAME_NUMBER 0x2020 /* frame number */ -+#define USB_FIFO_ADDR 0x2028 /* address of SIE FIFO RAM */ -+#define USB_FIFO_CMD 0x202A /* SIE FIFO RAM access command */ -+#define USB_FIFO_DATA 0x2030 /* SIE FIFO RAM data */ -+/* Endpoint Registers */ -+#define EP0_SETUPA 0x20F8 /* EP 0 setup packet lower byte */ -+#define EP0_SETUPB 0x20FC /* EP 0 setup packet higher byte */ -+#define USB_EP0_CFG 0x2104 /* EP 0 configure */ -+#define USB_EP0_CTL 0x2108 /* EP 0 control */ -+#define USB_EP0_STAT 0x210C /* EP 0 status */ -+#define USB_EP0_IRQSTAT 0x2110 /* EP 0 interrupt status */ -+#define USB_EP0_IRQEN 0x2114 /* EP 0 interrupt enable */ -+#define USB_EP0_MAXPKT 0x2118 /* EP 0 max packet size */ -+#define USB_EP0_BC 0x2120 /* EP 0 FIFO byte counter */ -+#define USB_EPA_CFG 0x2144 /* EP A configure */ -+#define USB_EPA_CFG_0 0x2144 /* EP A configure */ -+#define USB_EPA_CFG_1 0x2145 /* EP A configure */ -+#define USB_EPA_CFG_2 0x2146 /* EP A configure */ -+#define USB_EPA_CFG_3 0x2147 /* EP A configure */ -+#define USB_EPA_CTL 0x2148 /* EP A control */ -+#define USB_EPA_CTL_0 0x2148 /* EP A control */ -+#define USB_EPA_CTL_1 0x2149 /* EP A control */ -+#define USB_EPA_CTL_2 0x214A /* EP A control */ -+#define USB_EPA_CTL_3 0x214B /* EP A control */ -+#define USB_EPA_STAT 0x214C /* EP A status */ -+#define USB_EPA_IRQSTAT 0x2150 /* EP A interrupt status */ -+#define USB_EPA_IRQEN 0x2154 /* EP A interrupt enable */ -+#define USB_EPA_MAXPKT 0x2158 /* EP A max packet size */ -+#define USB_EPA_MAXPKT_0 0x2158 /* EP A max packet size */ -+#define USB_EPA_MAXPKT_1 0x2159 /* EP A max packet size */ -+#define USB_EPA_MAXPKT_2 0x215A /* EP A max packet size */ -+#define USB_EPA_MAXPKT_3 0x215B /* EP A max packet size */ -+#define USB_EPA_FIFO_CFG 0x2160 /* EP A FIFO configure */ -+#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */ -+#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */ -+#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */ -+#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */ -+/* Debug Registers */ -+#define USB_PHYTSTDIS 0x2F04 /* PHY test disable */ -+#define USB_TOUT_VAL 0x2F08 /* USB time-out time */ -+#define USB_VDRCTRL 0x2F10 /* UTMI vendor signal control */ -+#define USB_VSTAIN 0x2F14 /* UTMI vendor signal status in */ -+#define USB_VLOADM 0x2F18 /* UTMI load vendor signal status in */ -+#define USB_VSTAOUT 0x2F1C /* UTMI vendor signal status out */ -+#define USB_UTMI_TST 0x2F80 /* UTMI test */ -+#define USB_UTMI_STATUS 0x2F84 /* UTMI status */ -+#define USB_TSTCTL 0x2F88 /* test control */ -+#define USB_TSTCTL2 0x2F8C /* test control 2 */ -+#define USB_PID_FORCE 0x2F90 /* force PID */ -+#define USB_PKTERR_CNT 0x2F94 /* packet error counter */ -+#define USB_RXERR_CNT 0x2F98 /* RX error counter */ -+#define USB_MEM_BIST 0x2F9C /* MEM BIST test */ -+#define USB_SLBBIST 0x2FA0 /* self-loop-back BIST */ -+#define USB_CNTTEST 0x2FA4 /* counter test */ -+#define USB_PHYTST 0x2FC0 /* USB PHY test */ -+#define USB_DBGIDX 0x2FF0 /* select individual block debug signal */ -+#define USB_DBGMUX 0x2FF4 /* debug signal module mux */ -+ -+/* -+ * SYS registers -+ */ -+/* demod control registers */ -+#define SYS_SYS0 0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */ -+#define SYS_DEMOD_CTL 0x3000 /* control register for DVB-T demodulator */ -+/* GPIO registers */ -+#define SYS_GPIO_OUT_VAL 0x3001 /* output value of GPIO */ -+#define SYS_GPIO_IN_VAL 0x3002 /* input value of GPIO */ -+#define SYS_GPIO_OUT_EN 0x3003 /* output enable of GPIO */ -+#define SYS_SYS1 0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */ -+#define SYS_GPIO_DIR 0x3004 /* direction control for GPIO */ -+#define SYS_SYSINTE 0x3005 /* system interrupt enable */ -+#define SYS_SYSINTS 0x3006 /* system interrupt status */ -+#define SYS_GPIO_CFG0 0x3007 /* PAD configuration for GPIO0-GPIO3 */ -+#define SYS_SYS2 0x3008 /* include GP_CFG1 and 3 reserved bytes */ -+#define SYS_GPIO_CFG1 0x3008 /* PAD configuration for GPIO4 */ -+#define SYS_DEMOD_CTL1 0x300B -+ -+/* IrDA registers */ -+#define SYS_IRRC_PSR 0x3020 /* IR protocol selection */ -+#define SYS_IRRC_PER 0x3024 /* IR protocol extension */ -+#define SYS_IRRC_SF 0x3028 /* IR sampling frequency */ -+#define SYS_IRRC_DPIR 0x302C /* IR data package interval */ -+#define SYS_IRRC_CR 0x3030 /* IR control */ -+#define SYS_IRRC_RP 0x3034 /* IR read port */ -+#define SYS_IRRC_SR 0x3038 /* IR status */ -+/* I2C master registers */ -+#define SYS_I2CCR 0x3040 /* I2C clock */ -+#define SYS_I2CMCR 0x3044 /* I2C master control */ -+#define SYS_I2CMSTR 0x3048 /* I2C master SCL timing */ -+#define SYS_I2CMSR 0x304C /* I2C master status */ -+#define SYS_I2CMFR 0x3050 /* I2C master FIFO */ -+ -+/* -+ * IR registers -+ */ -+#define IR_RX_BUF 0xFC00 -+#define IR_RX_IE 0xFD00 -+#define IR_RX_IF 0xFD01 -+#define IR_RX_CTRL 0xFD02 -+#define IR_RX_CFG 0xFD03 -+#define IR_MAX_DURATION0 0xFD04 -+#define IR_MAX_DURATION1 0xFD05 -+#define IR_IDLE_LEN0 0xFD06 -+#define IR_IDLE_LEN1 0xFD07 -+#define IR_GLITCH_LEN 0xFD08 -+#define IR_RX_BUF_CTRL 0xFD09 -+#define IR_RX_BUF_DATA 0xFD0A -+#define IR_RX_BC 0xFD0B -+#define IR_RX_CLK 0xFD0C -+#define IR_RX_C_COUNT_L 0xFD0D -+#define IR_RX_C_COUNT_H 0xFD0E -+#define IR_SUSPEND_CTRL 0xFD10 -+#define IR_ERR_TOL_CTRL 0xFD11 -+#define IR_UNIT_LEN 0xFD12 -+#define IR_ERR_TOL_LEN 0xFD13 -+#define IR_MAX_H_TOL_LEN 0xFD14 -+#define IR_MAX_L_TOL_LEN 0xFD15 -+#define IR_MASK_CTRL 0xFD16 -+#define IR_MASK_DATA 0xFD17 -+#define IR_RES_MASK_ADDR 0xFD18 -+#define IR_RES_MASK_T_LEN 0xFD19 -+ -+#endif -Index: linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-jpeg/jpeg-core.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-core.c -@@ -32,10 +32,9 @@ - - static struct s5p_jpeg_fmt formats_enc[] = { - { -- .name = "YUV 4:2:0 planar, YCbCr", -- .fourcc = V4L2_PIX_FMT_YUV420, -- .depth = 12, -- .colplanes = 3, -+ .name = "JPEG JFIF", -+ .fourcc = V4L2_PIX_FMT_JPEG, -+ .colplanes = 1, - .types = MEM2MEM_CAPTURE, - }, - { -@@ -43,7 +42,7 @@ static struct s5p_jpeg_fmt formats_enc[] - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .colplanes = 1, -- .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, -+ .types = MEM2MEM_OUTPUT, - }, - { - .name = "RGB565", -@@ -203,6 +202,16 @@ static const unsigned char hactblg0[162] - 0xf9, 0xfa - }; - -+static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) -+{ -+ return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler); -+} -+ -+static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) -+{ -+ return container_of(fh, struct s5p_jpeg_ctx, fh); -+} -+ - static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, - unsigned long tab, int len) - { -@@ -269,6 +278,7 @@ static int queue_init(void *priv, struct - struct vb2_queue *dst_vq); - static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, - __u32 pixelformat); -+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx); - - static int s5p_jpeg_open(struct file *file) - { -@@ -276,12 +286,18 @@ static int s5p_jpeg_open(struct file *fi - struct video_device *vfd = video_devdata(file); - struct s5p_jpeg_ctx *ctx; - struct s5p_jpeg_fmt *out_fmt; -+ int ret = 0; - - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); - if (!ctx) - return -ENOMEM; - -- file->private_data = ctx; -+ v4l2_fh_init(&ctx->fh, vfd); -+ /* Use separate control handler per file handle */ -+ ctx->fh.ctrl_handler = &ctx->ctrl_handler; -+ file->private_data = &ctx->fh; -+ v4l2_fh_add(&ctx->fh); -+ - ctx->jpeg = jpeg; - if (vfd == jpeg->vfd_encoder) { - ctx->mode = S5P_JPEG_ENCODE; -@@ -291,24 +307,35 @@ static int s5p_jpeg_open(struct file *fi - out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); - } - -+ ret = s5p_jpeg_controls_create(ctx); -+ if (ret < 0) -+ goto error; -+ - ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); - if (IS_ERR(ctx->m2m_ctx)) { -- int err = PTR_ERR(ctx->m2m_ctx); -- kfree(ctx); -- return err; -+ ret = PTR_ERR(ctx->m2m_ctx); -+ goto error; - } - - ctx->out_q.fmt = out_fmt; - ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); -- - return 0; -+ -+error: -+ v4l2_fh_del(&ctx->fh); -+ v4l2_fh_exit(&ctx->fh); -+ kfree(ctx); -+ return ret; - } - - static int s5p_jpeg_release(struct file *file) - { -- struct s5p_jpeg_ctx *ctx = file->private_data; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); - - v4l2_m2m_ctx_release(ctx->m2m_ctx); -+ v4l2_ctrl_handler_free(&ctx->ctrl_handler); -+ v4l2_fh_del(&ctx->fh); -+ v4l2_fh_exit(&ctx->fh); - kfree(ctx); - - return 0; -@@ -317,14 +344,14 @@ static int s5p_jpeg_release(struct file - static unsigned int s5p_jpeg_poll(struct file *file, - struct poll_table_struct *wait) - { -- struct s5p_jpeg_ctx *ctx = file->private_data; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); - - return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); - } - - static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) - { -- struct s5p_jpeg_ctx *ctx = file->private_data; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); - - return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); - } -@@ -448,7 +475,7 @@ static bool s5p_jpeg_parse_hdr(struct s5 - static int s5p_jpeg_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - if (ctx->mode == S5P_JPEG_ENCODE) { - strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder", -@@ -497,9 +524,7 @@ static int enum_fmt(struct s5p_jpeg_fmt - static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) - { -- struct s5p_jpeg_ctx *ctx; -- -- ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - if (ctx->mode == S5P_JPEG_ENCODE) - return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, -@@ -511,9 +536,7 @@ static int s5p_jpeg_enum_fmt_vid_cap(str - static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) - { -- struct s5p_jpeg_ctx *ctx; -- -- ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - if (ctx->mode == S5P_JPEG_ENCODE) - return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, -@@ -538,7 +561,7 @@ static int s5p_jpeg_g_fmt(struct file *f - struct vb2_queue *vq; - struct s5p_jpeg_q_data *q_data = NULL; - struct v4l2_pix_format *pix = &f->fmt.pix; -- struct s5p_jpeg_ctx *ct = priv; -+ struct s5p_jpeg_ctx *ct = fh_to_ctx(priv); - - vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); - if (!vq) -@@ -659,8 +682,8 @@ static int vidioc_try_fmt(struct v4l2_fo - static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) - { -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - struct s5p_jpeg_fmt *fmt; -- struct s5p_jpeg_ctx *ctx = priv; - - fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); - if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { -@@ -676,8 +699,8 @@ static int s5p_jpeg_try_fmt_vid_cap(stru - static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) - { -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - struct s5p_jpeg_fmt *fmt; -- struct s5p_jpeg_ctx *ctx = priv; - - fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); - if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { -@@ -728,7 +751,7 @@ static int s5p_jpeg_s_fmt_vid_cap(struct - if (ret) - return ret; - -- return s5p_jpeg_s_fmt(priv, f); -+ return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); - } - - static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, -@@ -740,13 +763,13 @@ static int s5p_jpeg_s_fmt_vid_out(struct - if (ret) - return ret; - -- return s5p_jpeg_s_fmt(priv, f); -+ return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); - } - - static int s5p_jpeg_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); - } -@@ -754,14 +777,14 @@ static int s5p_jpeg_reqbufs(struct file - static int s5p_jpeg_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); - } - - static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); - } -@@ -769,7 +792,7 @@ static int s5p_jpeg_qbuf(struct file *fi - static int s5p_jpeg_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); - } -@@ -777,7 +800,7 @@ static int s5p_jpeg_dqbuf(struct file *f - static int s5p_jpeg_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); - } -@@ -785,7 +808,7 @@ static int s5p_jpeg_streamon(struct file - static int s5p_jpeg_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); - } -@@ -793,7 +816,7 @@ static int s5p_jpeg_streamoff(struct fil - int s5p_jpeg_g_selection(struct file *file, void *priv, - struct v4l2_selection *s) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); - - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && - s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -@@ -822,33 +845,89 @@ int s5p_jpeg_g_selection(struct file *fi - return 0; - } - --static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv, -- struct v4l2_jpegcompression *compr) -+/* -+ * V4L2 controls -+ */ -+ -+static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); -+ struct s5p_jpeg *jpeg = ctx->jpeg; -+ unsigned long flags; - -- if (ctx->mode == S5P_JPEG_DECODE) -- return -ENOTTY; -+ switch (ctrl->id) { -+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: -+ spin_lock_irqsave(&jpeg->slock, flags); -+ -+ WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY); -+ if (ctx->subsampling > 2) -+ ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; -+ else -+ ctrl->val = ctx->subsampling; -+ spin_unlock_irqrestore(&jpeg->slock, flags); -+ break; -+ } - -- memset(compr, 0, sizeof(*compr)); -- compr->quality = ctx->compr_quality; -+ return 0; -+} -+ -+static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ctx->jpeg->slock, flags); -+ -+ switch (ctrl->id) { -+ case V4L2_CID_JPEG_COMPRESSION_QUALITY: -+ ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val; -+ break; -+ case V4L2_CID_JPEG_RESTART_INTERVAL: -+ ctx->restart_interval = ctrl->val; -+ break; -+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: -+ ctx->subsampling = ctrl->val; -+ break; -+ } - -+ spin_unlock_irqrestore(&ctx->jpeg->slock, flags); - return 0; - } - --static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv, -- struct v4l2_jpegcompression *compr) -+static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = { -+ .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl, -+ .s_ctrl = s5p_jpeg_s_ctrl, -+}; -+ -+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) - { -- struct s5p_jpeg_ctx *ctx = priv; -+ unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */ -+ struct v4l2_ctrl *ctrl; - -- if (ctx->mode == S5P_JPEG_DECODE) -- return -ENOTTY; -+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); - -- compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST, -- S5P_JPEG_COMPR_QUAL_WORST); -+ if (ctx->mode == S5P_JPEG_ENCODE) { -+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, -+ V4L2_CID_JPEG_COMPRESSION_QUALITY, -+ 0, 3, 1, 3); -+ -+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, -+ V4L2_CID_JPEG_RESTART_INTERVAL, -+ 0, 3, 0xffff, 0); -+ mask = ~0x06; /* 422, 420 */ -+ } -+ -+ ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, -+ V4L2_CID_JPEG_CHROMA_SUBSAMPLING, -+ V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask, -+ V4L2_JPEG_CHROMA_SUBSAMPLING_422); - -- ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality; -+ if (ctx->ctrl_handler.error) -+ return ctx->ctrl_handler.error; - -+ if (ctx->mode == S5P_JPEG_DECODE) -+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | -+ V4L2_CTRL_FLAG_READ_ONLY; - return 0; - } - -@@ -877,9 +956,6 @@ static const struct v4l2_ioctl_ops s5p_j - .vidioc_streamoff = s5p_jpeg_streamoff, - - .vidioc_g_selection = s5p_jpeg_g_selection, -- -- .vidioc_g_jpegcomp = s5p_jpeg_g_jpegcomp, -- .vidioc_s_jpegcomp = s5p_jpeg_s_jpegcomp, - }; - - /* -@@ -908,13 +984,8 @@ static void s5p_jpeg_device_run(void *pr - jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); - else - jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); -- if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) -- jpeg_subsampling_mode(jpeg->regs, -- S5P_JPEG_SUBSAMPLING_422); -- else -- jpeg_subsampling_mode(jpeg->regs, -- S5P_JPEG_SUBSAMPLING_420); -- jpeg_dri(jpeg->regs, 0); -+ jpeg_subsampling_mode(jpeg->regs, ctx->subsampling); -+ jpeg_dri(jpeg->regs, ctx->restart_interval); - jpeg_x(jpeg->regs, ctx->out_q.w); - jpeg_y(jpeg->regs, ctx->out_q.h); - jpeg_imgadr(jpeg->regs, src_addr); -@@ -953,14 +1024,18 @@ static void s5p_jpeg_device_run(void *pr - jpeg_htbl_dc(jpeg->regs, 2); - jpeg_htbl_ac(jpeg->regs, 3); - jpeg_htbl_dc(jpeg->regs, 3); -- } else { -+ } else { /* S5P_JPEG_DECODE */ - jpeg_rst_int_enable(jpeg->regs, true); - jpeg_data_num_int_enable(jpeg->regs, true); - jpeg_final_mcu_num_int_enable(jpeg->regs, true); -- jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); -+ if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) -+ jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); -+ else -+ jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420); - jpeg_jpgadr(jpeg->regs, src_addr); - jpeg_imgadr(jpeg->regs, dst_addr); - } -+ - jpeg_start(jpeg->regs); - } - -@@ -1162,6 +1237,8 @@ static irqreturn_t s5p_jpeg_irq(int irq, - bool timer_elapsed = false; - bool op_completed = false; - -+ spin_lock(&jpeg->slock); -+ - curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); - - src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); -@@ -1192,6 +1269,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, - v4l2_m2m_buf_done(dst_buf, state); - v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); - -+ curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs); -+ spin_unlock(&jpeg->slock); -+ - jpeg_clear_int(jpeg->regs); - - return IRQ_HANDLED; -@@ -1215,6 +1295,7 @@ static int s5p_jpeg_probe(struct platfor - return -ENOMEM; - - mutex_init(&jpeg->lock); -+ spin_lock_init(&jpeg->slock); - jpeg->dev = &pdev->dev; - - /* memory-mapped registers */ -Index: linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-core.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-jpeg/jpeg-core.h -+++ linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-core.h -@@ -14,6 +14,8 @@ - #define JPEG_CORE_H_ - - #include -+#include -+#include - - #define S5P_JPEG_M2M_NAME "s5p-jpeg" - -@@ -47,6 +49,7 @@ - /** - * struct s5p_jpeg - JPEG IP abstraction - * @lock: the mutex protecting this structure -+ * @slock: spinlock protecting the device contexts - * @v4l2_dev: v4l2 device for mem2mem mode - * @vfd_encoder: video device node for encoder mem2mem mode - * @vfd_decoder: video device node for decoder mem2mem mode -@@ -60,6 +63,7 @@ - */ - struct s5p_jpeg { - struct mutex lock; -+ struct spinlock slock; - - struct v4l2_device v4l2_dev; - struct video_device *vfd_encoder; -@@ -117,15 +121,20 @@ struct s5p_jpeg_q_data { - * @out_q: source (output) queue information - * @cap_fmt: destination (capture) queue queue information - * @hdr_parsed: set if header has been parsed during decompression -+ * @ctrl_handler: controls handler - */ - struct s5p_jpeg_ctx { - struct s5p_jpeg *jpeg; - unsigned int mode; -- unsigned int compr_quality; -+ unsigned short compr_quality; -+ unsigned short restart_interval; -+ unsigned short subsampling; - struct v4l2_m2m_ctx *m2m_ctx; - struct s5p_jpeg_q_data out_q; - struct s5p_jpeg_q_data cap_q; -+ struct v4l2_fh fh; - bool hdr_parsed; -+ struct v4l2_ctrl_handler ctrl_handler; - }; - - /** -Index: linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-hw.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-jpeg/jpeg-hw.h -+++ linux-3.3.x86_64/drivers/media/video/s5p-jpeg/jpeg-hw.h -@@ -13,6 +13,7 @@ - #define JPEG_HW_H_ - - #include -+#include - - #include "jpeg-hw.h" - #include "jpeg-regs.h" -@@ -25,8 +26,6 @@ - #define S5P_JPEG_DECODE 1 - #define S5P_JPEG_RAW_IN_565 0 - #define S5P_JPEG_RAW_IN_422 1 --#define S5P_JPEG_SUBSAMPLING_422 0 --#define S5P_JPEG_SUBSAMPLING_420 1 - #define S5P_JPEG_RAW_OUT_422 0 - #define S5P_JPEG_RAW_OUT_420 1 - -@@ -91,21 +90,26 @@ static inline void jpeg_proc_mode(void _ - writel(reg, regs + S5P_JPGMOD); - } - --static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode) -+static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode) - { - unsigned long reg, m; - -- m = S5P_SUBSAMPLING_MODE_422; -- if (mode == S5P_JPEG_SUBSAMPLING_422) -- m = S5P_SUBSAMPLING_MODE_422; -- else if (mode == S5P_JPEG_SUBSAMPLING_420) -+ if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420) - m = S5P_SUBSAMPLING_MODE_420; -+ else -+ m = S5P_SUBSAMPLING_MODE_422; -+ - reg = readl(regs + S5P_JPGMOD); - reg &= ~S5P_SUBSAMPLING_MODE_MASK; - reg |= m; - writel(reg, regs + S5P_JPGMOD); - } - -+static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs) -+{ -+ return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK; -+} -+ - static inline void jpeg_dri(void __iomem *regs, unsigned int dri) - { - unsigned long reg; -Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/fimc-core.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-core.c -@@ -1602,24 +1602,35 @@ static void fimc_clk_put(struct fimc_dev - { - int i; - for (i = 0; i < fimc->num_clocks; i++) { -- if (fimc->clock[i]) -- clk_put(fimc->clock[i]); -+ if (IS_ERR_OR_NULL(fimc->clock[i])) -+ continue; -+ clk_unprepare(fimc->clock[i]); -+ clk_put(fimc->clock[i]); -+ fimc->clock[i] = NULL; - } - } - - static int fimc_clk_get(struct fimc_dev *fimc) - { -- int i; -+ int i, ret; -+ - for (i = 0; i < fimc->num_clocks; i++) { - fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); -- if (!IS_ERR_OR_NULL(fimc->clock[i])) -- continue; -- dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n", -- fimc_clocks[i]); -- return -ENXIO; -+ if (IS_ERR(fimc->clock[i])) -+ goto err; -+ ret = clk_prepare(fimc->clock[i]); -+ if (ret < 0) { -+ clk_put(fimc->clock[i]); -+ fimc->clock[i] = NULL; -+ goto err; -+ } - } -- - return 0; -+err: -+ fimc_clk_put(fimc); -+ dev_err(&fimc->pdev->dev, "failed to get clock: %s\n", -+ fimc_clocks[i]); -+ return -ENXIO; - } - - static int fimc_m2m_suspend(struct fimc_dev *fimc) -@@ -1667,8 +1678,6 @@ static int fimc_probe(struct platform_de - struct s5p_platform_fimc *pdata; - int ret = 0; - -- dev_dbg(&pdev->dev, "%s():\n", __func__); -- - drv_data = (struct samsung_fimc_driverdata *) - platform_get_device_id(pdev)->driver_data; - -@@ -1678,7 +1687,7 @@ static int fimc_probe(struct platform_de - return -EINVAL; - } - -- fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL); -+ fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL); - if (!fimc) - return -ENOMEM; - -@@ -1689,51 +1698,35 @@ static int fimc_probe(struct platform_de - pdata = pdev->dev.platform_data; - fimc->pdata = pdata; - -- - init_waitqueue_head(&fimc->irq_queue); - spin_lock_init(&fimc->slock); - mutex_init(&fimc->lock); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (!res) { -- dev_err(&pdev->dev, "failed to find the registers\n"); -- ret = -ENOENT; -- goto err_info; -- } -- -- fimc->regs_res = request_mem_region(res->start, resource_size(res), -- dev_name(&pdev->dev)); -- if (!fimc->regs_res) { -- dev_err(&pdev->dev, "failed to obtain register region\n"); -- ret = -ENOENT; -- goto err_info; -- } -- -- fimc->regs = ioremap(res->start, resource_size(res)); -- if (!fimc->regs) { -- dev_err(&pdev->dev, "failed to map registers\n"); -- ret = -ENXIO; -- goto err_req_region; -+ fimc->regs = devm_request_and_ioremap(&pdev->dev, res); -+ if (fimc->regs == NULL) { -+ dev_err(&pdev->dev, "Failed to obtain io memory\n"); -+ return -ENOENT; - } - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -- if (!res) { -- dev_err(&pdev->dev, "failed to get IRQ resource\n"); -- ret = -ENXIO; -- goto err_regs_unmap; -+ if (res == NULL) { -+ dev_err(&pdev->dev, "Failed to get IRQ resource\n"); -+ return -ENXIO; - } - fimc->irq = res->start; - - fimc->num_clocks = MAX_FIMC_CLOCKS; - ret = fimc_clk_get(fimc); - if (ret) -- goto err_regs_unmap; -+ return ret; - clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); - clk_enable(fimc->clock[CLK_BUS]); - - platform_set_drvdata(pdev, fimc); - -- ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc); -+ ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler, -+ 0, pdev->name, fimc); - if (ret) { - dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); - goto err_clk; -@@ -1742,7 +1735,7 @@ static int fimc_probe(struct platform_de - pm_runtime_enable(&pdev->dev); - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) -- goto err_irq; -+ goto err_clk; - /* Initialize contiguous memory allocator */ - fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); - if (IS_ERR(fimc->alloc_ctx)) { -@@ -1757,17 +1750,8 @@ static int fimc_probe(struct platform_de - - err_pm: - pm_runtime_put(&pdev->dev); --err_irq: -- free_irq(fimc->irq, fimc); - err_clk: - fimc_clk_put(fimc); --err_regs_unmap: -- iounmap(fimc->regs); --err_req_region: -- release_resource(fimc->regs_res); -- kfree(fimc->regs_res); --err_info: -- kfree(fimc); - return ret; - } - -@@ -1854,11 +1838,6 @@ static int __devexit fimc_remove(struct - - clk_disable(fimc->clock[CLK_BUS]); - fimc_clk_put(fimc); -- free_irq(fimc->irq, fimc); -- iounmap(fimc->regs); -- release_resource(fimc->regs_res); -- kfree(fimc->regs_res); -- kfree(fimc); - - dev_info(&pdev->dev, "driver unloaded\n"); - return 0; -Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/mipi-csis.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/mipi-csis.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/mipi-csis.c -@@ -1,8 +1,8 @@ - /* - * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver - * -- * Copyright (C) 2011 Samsung Electronics Co., Ltd. -- * Contact: Sylwester Nawrocki, -+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. -+ * Sylwester Nawrocki, - * - * 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 -@@ -100,7 +100,6 @@ enum { - * @pads: CSIS pads array - * @sd: v4l2_subdev associated with CSIS device instance - * @pdev: CSIS platform device -- * @regs_res: requested I/O register memory resource - * @regs: mmaped I/O registers memory - * @clock: CSIS clocks - * @irq: requested s5p-mipi-csis irq number -@@ -113,7 +112,6 @@ struct csis_state { - struct media_pad pads[CSIS_PADS_NUM]; - struct v4l2_subdev sd; - struct platform_device *pdev; -- struct resource *regs_res; - void __iomem *regs; - struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; - struct clk *clock[NUM_CSIS_CLOCKS]; -@@ -258,26 +256,36 @@ static void s5pcsis_clk_put(struct csis_ - { - int i; - -- for (i = 0; i < NUM_CSIS_CLOCKS; i++) -- if (!IS_ERR_OR_NULL(state->clock[i])) -- clk_put(state->clock[i]); -+ for (i = 0; i < NUM_CSIS_CLOCKS; i++) { -+ if (IS_ERR_OR_NULL(state->clock[i])) -+ continue; -+ clk_unprepare(state->clock[i]); -+ clk_put(state->clock[i]); -+ state->clock[i] = NULL; -+ } - } - - static int s5pcsis_clk_get(struct csis_state *state) - { - struct device *dev = &state->pdev->dev; -- int i; -+ int i, ret; - - for (i = 0; i < NUM_CSIS_CLOCKS; i++) { - state->clock[i] = clk_get(dev, csi_clock_name[i]); -- if (IS_ERR(state->clock[i])) { -- s5pcsis_clk_put(state); -- dev_err(dev, "failed to get clock: %s\n", -- csi_clock_name[i]); -- return -ENXIO; -+ if (IS_ERR(state->clock[i])) -+ goto err; -+ ret = clk_prepare(state->clock[i]); -+ if (ret < 0) { -+ clk_put(state->clock[i]); -+ state->clock[i] = NULL; -+ goto err; - } - } - return 0; -+err: -+ s5pcsis_clk_put(state); -+ dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]); -+ return -ENXIO; - } - - static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) -@@ -480,12 +488,11 @@ static int __devinit s5pcsis_probe(struc - { - struct s5p_platform_mipi_csis *pdata; - struct resource *mem_res; -- struct resource *regs_res; - struct csis_state *state; - int ret = -ENOMEM; - int i; - -- state = kzalloc(sizeof(*state), GFP_KERNEL); -+ state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; - -@@ -495,52 +502,27 @@ static int __devinit s5pcsis_probe(struc - pdata = pdev->dev.platform_data; - if (pdata == NULL || pdata->phy_enable == NULL) { - dev_err(&pdev->dev, "Platform data not fully specified\n"); -- goto e_free; -+ return -EINVAL; - } - - if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || - pdata->lanes > CSIS0_MAX_LANES) { -- ret = -EINVAL; - dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", - pdata->lanes); -- goto e_free; -+ return -EINVAL; - } - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (!mem_res) { -- dev_err(&pdev->dev, "Failed to get IO memory region\n"); -- goto e_free; -- } -- -- regs_res = request_mem_region(mem_res->start, resource_size(mem_res), -- pdev->name); -- if (!regs_res) { -- dev_err(&pdev->dev, "Failed to request IO memory region\n"); -- goto e_free; -- } -- state->regs_res = regs_res; -- -- state->regs = ioremap(mem_res->start, resource_size(mem_res)); -- if (!state->regs) { -- dev_err(&pdev->dev, "Failed to remap IO region\n"); -- goto e_reqmem; -+ state->regs = devm_request_and_ioremap(&pdev->dev, mem_res); -+ if (state->regs == NULL) { -+ dev_err(&pdev->dev, "Failed to request and remap io memory\n"); -+ return -ENXIO; - } - -- ret = s5pcsis_clk_get(state); -- if (ret) -- goto e_unmap; -- -- clk_enable(state->clock[CSIS_CLK_MUX]); -- if (pdata->clk_rate) -- clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); -- else -- dev_WARN(&pdev->dev, "No clock frequency specified!\n"); -- - state->irq = platform_get_irq(pdev, 0); - if (state->irq < 0) { -- ret = state->irq; - dev_err(&pdev->dev, "Failed to get irq\n"); -- goto e_clkput; -+ return state->irq; - } - - for (i = 0; i < CSIS_NUM_SUPPLIES; i++) -@@ -549,12 +531,22 @@ static int __devinit s5pcsis_probe(struc - ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, - state->supplies); - if (ret) -+ return ret; -+ -+ ret = s5pcsis_clk_get(state); -+ if (ret) - goto e_clkput; - -- ret = request_irq(state->irq, s5pcsis_irq_handler, 0, -- dev_name(&pdev->dev), state); -+ clk_enable(state->clock[CSIS_CLK_MUX]); -+ if (pdata->clk_rate) -+ clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); -+ else -+ dev_WARN(&pdev->dev, "No clock frequency specified!\n"); -+ -+ ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler, -+ 0, dev_name(&pdev->dev), state); - if (ret) { -- dev_err(&pdev->dev, "request_irq failed\n"); -+ dev_err(&pdev->dev, "Interrupt request failed\n"); - goto e_regput; - } - -@@ -573,7 +565,7 @@ static int __devinit s5pcsis_probe(struc - ret = media_entity_init(&state->sd.entity, - CSIS_PADS_NUM, state->pads, 0); - if (ret < 0) -- goto e_irqfree; -+ goto e_clkput; - - /* This allows to retrieve the platform device id by the host driver */ - v4l2_set_subdevdata(&state->sd, pdev); -@@ -582,22 +574,13 @@ static int __devinit s5pcsis_probe(struc - platform_set_drvdata(pdev, &state->sd); - - pm_runtime_enable(&pdev->dev); -- - return 0; - --e_irqfree: -- free_irq(state->irq, state); - e_regput: - regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); - e_clkput: - clk_disable(state->clock[CSIS_CLK_MUX]); - s5pcsis_clk_put(state); --e_unmap: -- iounmap(state->regs); --e_reqmem: -- release_mem_region(regs_res->start, resource_size(regs_res)); --e_free: -- kfree(state); - return ret; - } - -@@ -699,21 +682,15 @@ static int __devexit s5pcsis_remove(stru - { - struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct csis_state *state = sd_to_csis_state(sd); -- struct resource *res = state->regs_res; - - pm_runtime_disable(&pdev->dev); -- s5pcsis_suspend(&pdev->dev); -+ s5pcsis_pm_suspend(&pdev->dev, false); - clk_disable(state->clock[CSIS_CLK_MUX]); - pm_runtime_set_suspended(&pdev->dev); -- - s5pcsis_clk_put(state); - regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); - - media_entity_cleanup(&state->sd.entity); -- free_irq(state->irq, state); -- iounmap(state->regs); -- release_mem_region(res->start, resource_size(res)); -- kfree(state); - - return 0; - } -Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-core.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/fimc-core.h -+++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-core.h -@@ -434,7 +434,6 @@ struct fimc_ctx; - * @num_clocks: the number of clocks managed by this device instance - * @clock: clocks required for FIMC operation - * @regs: the mapped hardware registers -- * @regs_res: the resource claimed for IO registers - * @irq: FIMC interrupt number - * @irq_queue: interrupt handler waitqueue - * @v4l2_dev: root v4l2_device -@@ -454,7 +453,6 @@ struct fimc_dev { - u16 num_clocks; - struct clk *clock[MAX_FIMC_CLOCKS]; - void __iomem *regs; -- struct resource *regs_res; - int irq; - wait_queue_head_t irq_queue; - struct v4l2_device *v4l2_dev; -Index: linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-capture.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-fimc/fimc-capture.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-fimc/fimc-capture.c -@@ -1019,52 +1019,117 @@ static int fimc_cap_dqbuf(struct file *f - return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); - } - --static int fimc_cap_cropcap(struct file *file, void *fh, -- struct v4l2_cropcap *cr) -+static int fimc_cap_create_bufs(struct file *file, void *priv, -+ struct v4l2_create_buffers *create) - { - struct fimc_dev *fimc = video_drvdata(file); -- struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; - -- if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) -- return -EINVAL; -+ return vb2_create_bufs(&fimc->vid_cap.vbq, create); -+} - -- cr->bounds.left = 0; -- cr->bounds.top = 0; -- cr->bounds.width = f->o_width; -- cr->bounds.height = f->o_height; -- cr->defrect = cr->bounds; -+static int fimc_cap_prepare_buf(struct file *file, void *priv, -+ struct v4l2_buffer *b) -+{ -+ struct fimc_dev *fimc = video_drvdata(file); - -- return 0; -+ return vb2_prepare_buf(&fimc->vid_cap.vbq, b); - } - --static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) -+static int fimc_cap_g_selection(struct file *file, void *fh, -+ struct v4l2_selection *s) - { - struct fimc_dev *fimc = video_drvdata(file); -- struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; -+ struct fimc_ctx *ctx = fimc->vid_cap.ctx; -+ struct fimc_frame *f = &ctx->s_frame; - -- cr->c.left = f->offs_h; -- cr->c.top = f->offs_v; -- cr->c.width = f->width; -- cr->c.height = f->height; -+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) -+ return -EINVAL; - -- return 0; -+ switch (s->target) { -+ case V4L2_SEL_TGT_COMPOSE_DEFAULT: -+ case V4L2_SEL_TGT_COMPOSE_BOUNDS: -+ f = &ctx->d_frame; -+ case V4L2_SEL_TGT_CROP_BOUNDS: -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ s->r.left = 0; -+ s->r.top = 0; -+ s->r.width = f->o_width; -+ s->r.height = f->o_height; -+ return 0; -+ -+ case V4L2_SEL_TGT_COMPOSE_ACTIVE: -+ f = &ctx->d_frame; -+ case V4L2_SEL_TGT_CROP_ACTIVE: -+ s->r.left = f->offs_h; -+ s->r.top = f->offs_v; -+ s->r.width = f->width; -+ s->r.height = f->height; -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ -+int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) -+{ -+ if (a->left < b->left || a->top < b->top) -+ return 0; -+ if (a->left + a->width > b->left + b->width) -+ return 0; -+ if (a->top + a->height > b->top + b->height) -+ return 0; -+ -+ return 1; - } - --static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) -+static int fimc_cap_s_selection(struct file *file, void *fh, -+ struct v4l2_selection *s) - { - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; -- struct fimc_frame *ff; -+ struct v4l2_rect rect = s->r; -+ struct fimc_frame *f; - unsigned long flags; -+ unsigned int pad; -+ -+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) -+ return -EINVAL; -+ -+ switch (s->target) { -+ case V4L2_SEL_TGT_COMPOSE_DEFAULT: -+ case V4L2_SEL_TGT_COMPOSE_BOUNDS: -+ case V4L2_SEL_TGT_COMPOSE_ACTIVE: -+ f = &ctx->d_frame; -+ pad = FIMC_SD_PAD_SOURCE; -+ break; -+ case V4L2_SEL_TGT_CROP_BOUNDS: -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ case V4L2_SEL_TGT_CROP_ACTIVE: -+ f = &ctx->s_frame; -+ pad = FIMC_SD_PAD_SINK; -+ break; -+ default: -+ return -EINVAL; -+ } - -- fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK); -- ff = &ctx->s_frame; -+ fimc_capture_try_crop(ctx, &rect, pad); - -+ if (s->flags & V4L2_SEL_FLAG_LE && -+ !enclosed_rectangle(&rect, &s->r)) -+ return -ERANGE; -+ -+ if (s->flags & V4L2_SEL_FLAG_GE && -+ !enclosed_rectangle(&s->r, &rect)) -+ return -ERANGE; -+ -+ s->r = rect; - spin_lock_irqsave(&fimc->slock, flags); -- set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height); -- set_bit(ST_CAPT_APPLY_CFG, &fimc->state); -+ set_frame_crop(f, s->r.left, s->r.top, s->r.width, -+ s->r.height); - spin_unlock_irqrestore(&fimc->slock, flags); - -+ set_bit(ST_CAPT_APPLY_CFG, &fimc->state); - return 0; - } - -@@ -1082,12 +1147,14 @@ static const struct v4l2_ioctl_ops fimc_ - .vidioc_qbuf = fimc_cap_qbuf, - .vidioc_dqbuf = fimc_cap_dqbuf, - -+ .vidioc_prepare_buf = fimc_cap_prepare_buf, -+ .vidioc_create_bufs = fimc_cap_create_bufs, -+ - .vidioc_streamon = fimc_cap_streamon, - .vidioc_streamoff = fimc_cap_streamoff, - -- .vidioc_g_crop = fimc_cap_g_crop, -- .vidioc_s_crop = fimc_cap_s_crop, -- .vidioc_cropcap = fimc_cap_cropcap, -+ .vidioc_g_selection = fimc_cap_g_selection, -+ .vidioc_s_selection = fimc_cap_s_selection, - - .vidioc_enum_input = fimc_cap_enum_input, - .vidioc_s_input = fimc_cap_s_input, -Index: linux-3.3.x86_64/drivers/media/video/videobuf2-vmalloc.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/videobuf2-vmalloc.c -+++ linux-3.3.x86_64/drivers/media/video/videobuf2-vmalloc.c -@@ -10,6 +10,7 @@ - * the Free Software Foundation. - */ - -+#include - #include - #include - #include -@@ -22,6 +23,7 @@ - struct vb2_vmalloc_buf { - void *vaddr; - struct page **pages; -+ struct vm_area_struct *vma; - int write; - unsigned long size; - unsigned int n_pages; -@@ -71,6 +73,8 @@ static void *vb2_vmalloc_get_userptr(voi - struct vb2_vmalloc_buf *buf; - unsigned long first, last; - int n_pages, offset; -+ struct vm_area_struct *vma; -+ dma_addr_t physp; - - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) -@@ -80,23 +84,37 @@ static void *vb2_vmalloc_get_userptr(voi - offset = vaddr & ~PAGE_MASK; - buf->size = size; - -- first = vaddr >> PAGE_SHIFT; -- last = (vaddr + size - 1) >> PAGE_SHIFT; -- buf->n_pages = last - first + 1; -- buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL); -- if (!buf->pages) -- goto fail_pages_array_alloc; -- -- /* current->mm->mmap_sem is taken by videobuf2 core */ -- n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK, -- buf->n_pages, write, 1, /* force */ -- buf->pages, NULL); -- if (n_pages != buf->n_pages) -- goto fail_get_user_pages; -- -- buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL); -- if (!buf->vaddr) -- goto fail_get_user_pages; -+ -+ vma = find_vma(current->mm, vaddr); -+ if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) { -+ if (vb2_get_contig_userptr(vaddr, size, &vma, &physp)) -+ goto fail_pages_array_alloc; -+ buf->vma = vma; -+ buf->vaddr = ioremap_nocache(physp, size); -+ if (!buf->vaddr) -+ goto fail_pages_array_alloc; -+ } else { -+ first = vaddr >> PAGE_SHIFT; -+ last = (vaddr + size - 1) >> PAGE_SHIFT; -+ buf->n_pages = last - first + 1; -+ buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), -+ GFP_KERNEL); -+ if (!buf->pages) -+ goto fail_pages_array_alloc; -+ -+ /* current->mm->mmap_sem is taken by videobuf2 core */ -+ n_pages = get_user_pages(current, current->mm, -+ vaddr & PAGE_MASK, buf->n_pages, -+ write, 1, /* force */ -+ buf->pages, NULL); -+ if (n_pages != buf->n_pages) -+ goto fail_get_user_pages; -+ -+ buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, -+ PAGE_KERNEL); -+ if (!buf->vaddr) -+ goto fail_get_user_pages; -+ } - - buf->vaddr += offset; - return buf; -@@ -120,14 +138,20 @@ static void vb2_vmalloc_put_userptr(void - unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; - unsigned int i; - -- if (vaddr) -- vm_unmap_ram((void *)vaddr, buf->n_pages); -- for (i = 0; i < buf->n_pages; ++i) { -- if (buf->write) -- set_page_dirty_lock(buf->pages[i]); -- put_page(buf->pages[i]); -+ if (buf->pages) { -+ if (vaddr) -+ vm_unmap_ram((void *)vaddr, buf->n_pages); -+ for (i = 0; i < buf->n_pages; ++i) { -+ if (buf->write) -+ set_page_dirty_lock(buf->pages[i]); -+ put_page(buf->pages[i]); -+ } -+ kfree(buf->pages); -+ } else { -+ if (buf->vma) -+ vb2_put_vma(buf->vma); -+ iounmap(buf->vaddr); - } -- kfree(buf->pages); - kfree(buf); - } - -Index: linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-g2d/g2d.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d.c -@@ -178,6 +178,9 @@ static int g2d_s_ctrl(struct v4l2_ctrl * - { - struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx, - ctrl_handler); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ctx->dev->ctrl_lock, flags); - switch (ctrl->id) { - case V4L2_CID_COLORFX: - if (ctrl->val == V4L2_COLORFX_NEGATIVE) -@@ -185,10 +188,13 @@ static int g2d_s_ctrl(struct v4l2_ctrl * - else - ctx->rop = ROP4_COPY; - break; -- default: -- v4l2_err(&ctx->dev->v4l2_dev, "unknown control\n"); -- return -EINVAL; -+ -+ case V4L2_CID_HFLIP: -+ ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1); -+ break; -+ - } -+ spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); - return 0; - } - -@@ -200,11 +206,13 @@ int g2d_setup_ctrls(struct g2d_ctx *ctx) - { - struct g2d_dev *dev = ctx->dev; - -- v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1); -- if (ctx->ctrl_handler.error) { -- v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); -- return ctx->ctrl_handler.error; -- } -+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); -+ -+ ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, -+ V4L2_CID_HFLIP, 0, 1, 1, 0); -+ -+ ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, -+ V4L2_CID_VFLIP, 0, 1, 1, 0); - - v4l2_ctrl_new_std_menu( - &ctx->ctrl_handler, -@@ -215,10 +223,14 @@ int g2d_setup_ctrls(struct g2d_ctx *ctx) - V4L2_COLORFX_NONE); - - if (ctx->ctrl_handler.error) { -- v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); -- return ctx->ctrl_handler.error; -+ int err = ctx->ctrl_handler.error; -+ v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n"); -+ v4l2_ctrl_handler_free(&ctx->ctrl_handler); -+ return err; - } - -+ v4l2_ctrl_cluster(2, &ctx->ctrl_hflip); -+ - return 0; - } - -@@ -547,6 +559,7 @@ static void device_run(void *prv) - struct g2d_ctx *ctx = prv; - struct g2d_dev *dev = ctx->dev; - struct vb2_buffer *src, *dst; -+ unsigned long flags; - u32 cmd = 0; - - dev->curr = ctx; -@@ -557,6 +570,8 @@ static void device_run(void *prv) - clk_enable(dev->gate); - g2d_reset(dev); - -+ spin_lock_irqsave(&dev->ctrl_lock, flags); -+ - g2d_set_src_size(dev, &ctx->in); - g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0)); - -@@ -564,11 +579,15 @@ static void device_run(void *prv) - g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0)); - - g2d_set_rop4(dev, ctx->rop); -+ g2d_set_flip(dev, ctx->flip); -+ - if (ctx->in.c_width != ctx->out.c_width || - ctx->in.c_height != ctx->out.c_height) - cmd |= g2d_cmd_stretch(1); - g2d_set_cmd(dev, cmd); - g2d_start(dev); -+ -+ spin_unlock_irqrestore(&dev->ctrl_lock, flags); - } - - static irqreturn_t g2d_isr(int irq, void *prv) -@@ -658,7 +677,7 @@ static int g2d_probe(struct platform_dev - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; -- spin_lock_init(&dev->irqlock); -+ spin_lock_init(&dev->ctrl_lock); - mutex_init(&dev->mutex); - atomic_set(&dev->num_inst, 0); - init_waitqueue_head(&dev->irq_queue); -@@ -693,18 +712,30 @@ static int g2d_probe(struct platform_dev - goto unmap_regs; - } - -+ ret = clk_prepare(dev->clk); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to prepare g2d clock\n"); -+ goto put_clk; -+ } -+ - dev->gate = clk_get(&pdev->dev, "fimg2d"); - if (IS_ERR_OR_NULL(dev->gate)) { - dev_err(&pdev->dev, "failed to get g2d clock gate\n"); - ret = -ENXIO; -- goto put_clk; -+ goto unprep_clk; -+ } -+ -+ ret = clk_prepare(dev->gate); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to prepare g2d clock gate\n"); -+ goto put_clk_gate; - } - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, "failed to find IRQ\n"); - ret = -ENXIO; -- goto put_clk_gate; -+ goto unprep_clk_gate; - } - - dev->irq = res->start; -@@ -764,8 +795,12 @@ alloc_ctx_cleanup: - vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); - rel_irq: - free_irq(dev->irq, dev); -+unprep_clk_gate: -+ clk_unprepare(dev->gate); - put_clk_gate: - clk_put(dev->gate); -+unprep_clk: -+ clk_unprepare(dev->clk); - put_clk: - clk_put(dev->clk); - unmap_regs: -@@ -787,7 +822,9 @@ static int g2d_remove(struct platform_de - v4l2_device_unregister(&dev->v4l2_dev); - vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); - free_irq(dev->irq, dev); -+ clk_unprepare(dev->gate); - clk_put(dev->gate); -+ clk_unprepare(dev->clk); - clk_put(dev->clk); - iounmap(dev->regs); - release_resource(dev->res_regs); -Index: linux-3.3.x86_64/drivers/media/video/s5p-mfc/s5p_mfc_pm.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-mfc/s5p_mfc_pm.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-mfc/s5p_mfc_pm.c -@@ -41,15 +41,29 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev * - pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME); - if (IS_ERR(pm->clock_gate)) { - mfc_err("Failed to get clock-gating control\n"); -- ret = -ENOENT; -+ ret = PTR_ERR(pm->clock_gate); - goto err_g_ip_clk; - } -+ -+ ret = clk_prepare(pm->clock_gate); -+ if (ret) { -+ mfc_err("Failed to preapre clock-gating control\n"); -+ goto err_p_ip_clk; -+ } -+ - pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); - if (IS_ERR(pm->clock)) { - mfc_err("Failed to get MFC clock\n"); -- ret = -ENOENT; -+ ret = PTR_ERR(pm->clock); - goto err_g_ip_clk_2; - } -+ -+ ret = clk_prepare(pm->clock); -+ if (ret) { -+ mfc_err("Failed to prepare MFC clock\n"); -+ goto err_p_ip_clk_2; -+ } -+ - atomic_set(&pm->power, 0); - #ifdef CONFIG_PM_RUNTIME - pm->device = &dev->plat_dev->dev; -@@ -59,7 +73,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev * - atomic_set(&clk_ref, 0); - #endif - return 0; -+err_p_ip_clk_2: -+ clk_put(pm->clock); - err_g_ip_clk_2: -+ clk_unprepare(pm->clock_gate); -+err_p_ip_clk: - clk_put(pm->clock_gate); - err_g_ip_clk: - return ret; -@@ -67,7 +85,9 @@ err_g_ip_clk: - - void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) - { -+ clk_unprepare(pm->clock_gate); - clk_put(pm->clock_gate); -+ clk_unprepare(pm->clock); - clk_put(pm->clock); - #ifdef CONFIG_PM_RUNTIME - pm_runtime_disable(pm->device); -Index: linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d-hw.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-g2d/g2d-hw.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d-hw.c -@@ -77,6 +77,11 @@ void g2d_set_rop4(struct g2d_dev *d, u32 - w(r, ROP4_REG); - } - -+void g2d_set_flip(struct g2d_dev *d, u32 r) -+{ -+ w(r, SRC_MSK_DIRECT_REG); -+} -+ - u32 g2d_cmd_stretch(u32 e) - { - e &= 1; -Index: linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-g2d/g2d.h -+++ linux-3.3.x86_64/drivers/media/video/s5p-g2d/g2d.h -@@ -20,7 +20,7 @@ struct g2d_dev { - struct v4l2_m2m_dev *m2m_dev; - struct video_device *vfd; - struct mutex mutex; -- spinlock_t irqlock; -+ spinlock_t ctrl_lock; - atomic_t num_inst; - struct vb2_alloc_ctx *alloc_ctx; - struct resource *res_regs; -@@ -57,8 +57,11 @@ struct g2d_ctx { - struct v4l2_m2m_ctx *m2m_ctx; - struct g2d_frame in; - struct g2d_frame out; -+ struct v4l2_ctrl *ctrl_hflip; -+ struct v4l2_ctrl *ctrl_vflip; - struct v4l2_ctrl_handler ctrl_handler; - u32 rop; -+ u32 flip; - }; - - struct g2d_fmt { -@@ -77,6 +80,7 @@ void g2d_set_dst_addr(struct g2d_dev *d, - void g2d_start(struct g2d_dev *d); - void g2d_clear_int(struct g2d_dev *d); - void g2d_set_rop4(struct g2d_dev *d, u32 r); -+void g2d_set_flip(struct g2d_dev *d, u32 r); - u32 g2d_cmd_stretch(u32 e); - void g2d_set_cmd(struct g2d_dev *d, u32 c); - -Index: linux-3.3.x86_64/drivers/media/video/s5k6aa.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5k6aa.c -+++ linux-3.3.x86_64/drivers/media/video/s5k6aa.c -@@ -1582,8 +1582,8 @@ static int s5k6aa_probe(struct i2c_clien - s5k6aa->inv_vflip = pdata->vert_flip; - - sd = &s5k6aa->sd; -- strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); - v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); -+ strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); - - sd->internal_ops = &s5k6aa_subdev_internal_ops; - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -@@ -1663,18 +1663,7 @@ static struct i2c_driver s5k6aa_i2c_driv - .id_table = s5k6aa_id, - }; - --static int __init s5k6aa_init(void) --{ -- return i2c_add_driver(&s5k6aa_i2c_driver); --} -- --static void __exit s5k6aa_exit(void) --{ -- i2c_del_driver(&s5k6aa_i2c_driver); --} -- --module_init(s5k6aa_init); --module_exit(s5k6aa_exit); -+module_i2c_driver(s5k6aa_i2c_driver); - - MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); - MODULE_AUTHOR("Sylwester Nawrocki "); -Index: linux-3.3.x86_64/drivers/media/video/noon010pc30.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/noon010pc30.c -+++ linux-3.3.x86_64/drivers/media/video/noon010pc30.c -@@ -725,8 +725,8 @@ static int noon010_probe(struct i2c_clie - - mutex_init(&info->lock); - sd = &info->sd; -- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); - v4l2_i2c_subdev_init(sd, client, &noon010_ops); -+ strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); - - sd->internal_ops = &noon010_subdev_internal_ops; - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -@@ -844,18 +844,7 @@ static struct i2c_driver noon010_i2c_dri - .id_table = noon010_id, - }; - --static int __init noon010_init(void) --{ -- return i2c_add_driver(&noon010_i2c_driver); --} -- --static void __exit noon010_exit(void) --{ -- i2c_del_driver(&noon010_i2c_driver); --} -- --module_init(noon010_init); --module_exit(noon010_exit); -+module_i2c_driver(noon010_i2c_driver); - - MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver"); - MODULE_AUTHOR("Sylwester Nawrocki "); -Index: linux-3.3.x86_64/drivers/media/video/m5mols/m5mols_core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/m5mols/m5mols_core.c -+++ linux-3.3.x86_64/drivers/media/video/m5mols/m5mols_core.c -@@ -982,8 +982,8 @@ static int __devinit m5mols_probe(struct - } - - sd = &info->sd; -- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); - v4l2_i2c_subdev_init(sd, client, &m5mols_ops); -+ strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - sd->internal_ops = &m5mols_subdev_internal_ops; -@@ -1057,18 +1057,7 @@ static struct i2c_driver m5mols_i2c_driv - .id_table = m5mols_id, - }; - --static int __init m5mols_mod_init(void) --{ -- return i2c_add_driver(&m5mols_i2c_driver); --} -- --static void __exit m5mols_mod_exit(void) --{ -- i2c_del_driver(&m5mols_i2c_driver); --} -- --module_init(m5mols_mod_init); --module_exit(m5mols_mod_exit); -+module_i2c_driver(m5mols_i2c_driver); - - MODULE_AUTHOR("HeungJun Kim "); - MODULE_AUTHOR("Dongsoo Kim "); -Index: linux-3.3.x86_64/Documentation/video4linux/gspca.txt -=================================================================== ---- linux-3.3.x86_64.orig/Documentation/video4linux/gspca.txt -+++ linux-3.3.x86_64/Documentation/video4linux/gspca.txt -@@ -217,6 +217,7 @@ ov534_9 06f8:3003 Hercules Dualpix HD W - sonixj 06f8:3004 Hercules Classic Silver - sonixj 06f8:3008 Hercules Deluxe Optical Glass - pac7302 06f8:3009 Hercules Classic Link -+pac7302 06f8:301b Hercules Link - nw80x 0728:d001 AVerMedia Camguard - spca508 0733:0110 ViewQuest VQ110 - spca501 0733:0401 Intel Create and Share -Index: linux-3.3.x86_64/drivers/media/video/gspca/pac7302.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/gspca/pac7302.c -+++ linux-3.3.x86_64/drivers/media/video/gspca/pac7302.c -@@ -1,8 +1,8 @@ - /* -- * Pixart PAC7302 library -- * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li -+ * Pixart PAC7302 driver - * -- * V4L2 by Jean-Francois Moine -+ * Copyright (C) 2008-2012 Jean-Francois Moine -+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li - * - * Separated from Pixart PAC7311 library by Márton Németh - * Camera button input handling by Márton Németh -@@ -63,67 +63,61 @@ - - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - --#define MODULE_NAME "pac7302" -- - #include - #include - #include "gspca.h" -+/* Include pac common sof detection functions */ -+#include "pac_common.h" - --MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); -+MODULE_AUTHOR("Jean-Francois Moine , " -+ "Thomas Kaiser thomas@kaiser-linux.li"); - MODULE_DESCRIPTION("Pixart PAC7302"); - MODULE_LICENSE("GPL"); - -+enum e_ctrl { -+ BRIGHTNESS, -+ CONTRAST, -+ COLORS, -+ WHITE_BALANCE, -+ RED_BALANCE, -+ BLUE_BALANCE, -+ GAIN, -+ AUTOGAIN, -+ EXPOSURE, -+ VFLIP, -+ HFLIP, -+ NCTRLS /* number of controls */ -+}; -+ - /* specific webcam descriptor for pac7302 */ - struct sd { - struct gspca_dev gspca_dev; /* !! must be the first item */ - -- unsigned char brightness; -- unsigned char contrast; -- unsigned char colors; -- unsigned char white_balance; -- unsigned char red_balance; -- unsigned char blue_balance; -- unsigned char gain; -- unsigned char autogain; -- unsigned short exposure; -- __u8 hflip; -- __u8 vflip; -+ struct gspca_ctrl ctrls[NCTRLS]; -+ - u8 flags; - #define FL_HFLIP 0x01 /* mirrored by default */ - #define FL_VFLIP 0x02 /* vertical flipped by default */ - - u8 sof_read; -- u8 autogain_ignore_frames; -+ s8 autogain_ignore_frames; - - atomic_t avg_lum; - }; - - /* V4L2 controls supported by the driver */ --static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); --static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); --static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); --static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -+static void setbrightcont(struct gspca_dev *gspca_dev); -+static void setcolors(struct gspca_dev *gspca_dev); -+static void setwhitebalance(struct gspca_dev *gspca_dev); -+static void setredbalance(struct gspca_dev *gspca_dev); -+static void setbluebalance(struct gspca_dev *gspca_dev); -+static void setgain(struct gspca_dev *gspca_dev); -+static void setexposure(struct gspca_dev *gspca_dev); -+static void setautogain(struct gspca_dev *gspca_dev); -+static void sethvflip(struct gspca_dev *gspca_dev); - - static const struct ctrl sd_ctrls[] = { -- { -+[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, -@@ -132,13 +126,11 @@ static const struct ctrl sd_ctrls[] = { - #define BRIGHTNESS_MAX 0x20 - .maximum = BRIGHTNESS_MAX, - .step = 1, --#define BRIGHTNESS_DEF 0x10 -- .default_value = BRIGHTNESS_DEF, -+ .default_value = 0x10, - }, -- .set = sd_setbrightness, -- .get = sd_getbrightness, -+ .set_control = setbrightcont - }, -- { -+[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, -@@ -147,13 +139,11 @@ static const struct ctrl sd_ctrls[] = { - #define CONTRAST_MAX 255 - .maximum = CONTRAST_MAX, - .step = 1, --#define CONTRAST_DEF 127 -- .default_value = CONTRAST_DEF, -+ .default_value = 127, - }, -- .set = sd_setcontrast, -- .get = sd_getcontrast, -+ .set_control = setbrightcont - }, -- { -+[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, -@@ -162,13 +152,11 @@ static const struct ctrl sd_ctrls[] = { - #define COLOR_MAX 255 - .maximum = COLOR_MAX, - .step = 1, --#define COLOR_DEF 127 -- .default_value = COLOR_DEF, -+ .default_value = 127 - }, -- .set = sd_setcolors, -- .get = sd_getcolors, -+ .set_control = setcolors - }, -- { -+[WHITE_BALANCE] = { - { - .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, - .type = V4L2_CTRL_TYPE_INTEGER, -@@ -176,13 +164,11 @@ static const struct ctrl sd_ctrls[] = { - .minimum = 0, - .maximum = 255, - .step = 1, --#define WHITEBALANCE_DEF 4 -- .default_value = WHITEBALANCE_DEF, -+ .default_value = 4, - }, -- .set = sd_setwhitebalance, -- .get = sd_getwhitebalance, -+ .set_control = setwhitebalance - }, -- { -+[RED_BALANCE] = { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, -@@ -190,13 +176,11 @@ static const struct ctrl sd_ctrls[] = { - .minimum = 0, - .maximum = 3, - .step = 1, --#define REDBALANCE_DEF 1 -- .default_value = REDBALANCE_DEF, -+ .default_value = 1, - }, -- .set = sd_setredbalance, -- .get = sd_getredbalance, -+ .set_control = setredbalance - }, -- { -+[BLUE_BALANCE] = { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, -@@ -204,29 +188,25 @@ static const struct ctrl sd_ctrls[] = { - .minimum = 0, - .maximum = 3, - .step = 1, --#define BLUEBALANCE_DEF 1 -- .default_value = BLUEBALANCE_DEF, -+ .default_value = 1, - }, -- .set = sd_setbluebalance, -- .get = sd_getbluebalance, -+ .set_control = setbluebalance - }, -- { -+[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, --#define GAIN_MAX 255 -- .maximum = GAIN_MAX, -+ .maximum = 255, - .step = 1, - #define GAIN_DEF 127 - #define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ - .default_value = GAIN_DEF, - }, -- .set = sd_setgain, -- .get = sd_getgain, -+ .set_control = setgain - }, -- { -+[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, -@@ -238,10 +218,9 @@ static const struct ctrl sd_ctrls[] = { - #define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ - .default_value = EXPOSURE_DEF, - }, -- .set = sd_setexposure, -- .get = sd_getexposure, -+ .set_control = setexposure - }, -- { -+[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, -@@ -252,10 +231,9 @@ static const struct ctrl sd_ctrls[] = { - #define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, -- .set = sd_setautogain, -- .get = sd_getautogain, -+ .set_control = setautogain, - }, -- { -+[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, -@@ -263,13 +241,11 @@ static const struct ctrl sd_ctrls[] = { - .minimum = 0, - .maximum = 1, - .step = 1, --#define HFLIP_DEF 0 -- .default_value = HFLIP_DEF, -+ .default_value = 0, - }, -- .set = sd_sethflip, -- .get = sd_gethflip, -+ .set_control = sethvflip, - }, -- { -+[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, -@@ -277,11 +253,9 @@ static const struct ctrl sd_ctrls[] = { - .minimum = 0, - .maximum = 1, - .step = 1, --#define VFLIP_DEF 0 -- .default_value = VFLIP_DEF, -+ .default_value = 0, - }, -- .set = sd_setvflip, -- .get = sd_getvflip, -+ .set_control = sethvflip - }, - }; - -@@ -290,21 +264,21 @@ static const struct v4l2_pix_format vga_ - .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, - .colorspace = V4L2_COLORSPACE_JPEG, -- .priv = 0}, -+ }, - }; - - #define LOAD_PAGE3 255 - #define END_OF_SEQUENCE 0 - - /* pac 7302 */ --static const __u8 init_7302[] = { -+static const u8 init_7302[] = { - /* index,value */ - 0xff, 0x01, /* page 1 */ - 0x78, 0x00, /* deactivate */ - 0xff, 0x01, - 0x78, 0x40, /* led off */ - }; --static const __u8 start_7302[] = { -+static const u8 start_7302[] = { - /* index, len, [value]* */ - 0xff, 1, 0x00, /* page 0 */ - 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, -@@ -319,7 +293,7 @@ static const __u8 start_7302[] = { - 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, - 0x00, 0x54, 0x11, - 0x55, 1, 0x00, -- 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, -+ 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, - 0x6b, 1, 0x00, - 0x6e, 3, 0x08, 0x06, 0x00, - 0x72, 3, 0x00, 0xff, 0x00, -@@ -370,7 +344,7 @@ static const __u8 start_7302[] = { - - #define SKIP 0xaa - /* page 3 - the value SKIP says skip the index - see reg_w_page() */ --static const __u8 page3_7302[] = { -+static const u8 page3_7302[] = { - 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, - 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, - 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -@@ -394,7 +368,7 @@ static const __u8 page3_7302[] = { - }; - - static void reg_w_buf(struct gspca_dev *gspca_dev, -- __u8 index, -+ u8 index, - const u8 *buffer, int len) - { - int ret; -@@ -410,7 +384,7 @@ static void reg_w_buf(struct gspca_dev * - index, gspca_dev->usb_buf, len, - 500); - if (ret < 0) { -- pr_err("reg_w_buf failed index 0x%02x, error %d\n", -+ pr_err("reg_w_buf failed i: %02x error %d\n", - index, ret); - gspca_dev->usb_err = ret; - } -@@ -418,8 +392,8 @@ static void reg_w_buf(struct gspca_dev * - - - static void reg_w(struct gspca_dev *gspca_dev, -- __u8 index, -- __u8 value) -+ u8 index, -+ u8 value) - { - int ret; - -@@ -433,14 +407,14 @@ static void reg_w(struct gspca_dev *gspc - 0, index, gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { -- pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n", -+ pr_err("reg_w() failed i: %02x v: %02x error %d\n", - index, value, ret); - gspca_dev->usb_err = ret; - } - } - - static void reg_w_seq(struct gspca_dev *gspca_dev, -- const __u8 *seq, int len) -+ const u8 *seq, int len) - { - while (--len >= 0) { - reg_w(gspca_dev, seq[0], seq[1]); -@@ -450,7 +424,7 @@ static void reg_w_seq(struct gspca_dev * - - /* load the beginning of a page */ - static void reg_w_page(struct gspca_dev *gspca_dev, -- const __u8 *page, int len) -+ const u8 *page, int len) - { - int index; - int ret = 0; -@@ -468,7 +442,7 @@ static void reg_w_page(struct gspca_dev - 0, index, gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { -- pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n", -+ pr_err("reg_w_page() failed i: %02x v: %02x error %d\n", - index, page[index], ret); - gspca_dev->usb_err = ret; - break; -@@ -478,8 +452,8 @@ static void reg_w_page(struct gspca_dev - - /* output a variable sequence */ - static void reg_w_var(struct gspca_dev *gspca_dev, -- const __u8 *seq, -- const __u8 *page3, unsigned int page3_len) -+ const u8 *seq, -+ const u8 *page3, unsigned int page3_len) - { - int index, len; - -@@ -493,11 +467,13 @@ static void reg_w_var(struct gspca_dev * - reg_w_page(gspca_dev, page3, page3_len); - break; - default: -+#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - PDEBUG(D_ERR|D_STREAM, - "Incorrect variable sequence"); - return; - } -+#endif - while (len > 0) { - if (len < 8) { - reg_w_buf(gspca_dev, -@@ -524,21 +500,11 @@ static int sd_config(struct gspca_dev *g - - cam = &gspca_dev->cam; - -- PDEBUG(D_CONF, "Find Sensor PAC7302"); - cam->cam_mode = vga_mode; /* only 640x480 */ - cam->nmodes = ARRAY_SIZE(vga_mode); - -- sd->brightness = BRIGHTNESS_DEF; -- sd->contrast = CONTRAST_DEF; -- sd->colors = COLOR_DEF; -- sd->white_balance = WHITEBALANCE_DEF; -- sd->red_balance = REDBALANCE_DEF; -- sd->blue_balance = BLUEBALANCE_DEF; -- sd->gain = GAIN_DEF; -- sd->exposure = EXPOSURE_DEF; -- sd->autogain = AUTOGAIN_DEF; -- sd->hflip = HFLIP_DEF; -- sd->vflip = VFLIP_DEF; -+ gspca_dev->cam.ctrls = sd->ctrls; -+ - sd->flags = id->driver_info; - return 0; - } -@@ -548,19 +514,19 @@ static void setbrightcont(struct gspca_d - { - struct sd *sd = (struct sd *) gspca_dev; - int i, v; -- static const __u8 max[10] = -+ static const u8 max[10] = - {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, - 0xd4, 0xec}; -- static const __u8 delta[10] = -+ static const u8 delta[10] = - {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, - 0x11, 0x0b}; - - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - for (i = 0; i < 10; i++) { - v = max[i]; -- v += (sd->brightness - BRIGHTNESS_MAX) -+ v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX) - * 150 / BRIGHTNESS_MAX; /* 200 ? */ -- v -= delta[i] * sd->contrast / CONTRAST_MAX; -+ v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX; - if (v < 0) - v = 0; - else if (v > 0xff) -@@ -584,12 +550,11 @@ static void setcolors(struct gspca_dev * - reg_w(gspca_dev, 0x11, 0x01); - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - for (i = 0; i < 9; i++) { -- v = a[i] * sd->colors / COLOR_MAX + b[i]; -+ v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i]; - reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); - reg_w(gspca_dev, 0x0f + 2 * i + 1, v); - } - reg_w(gspca_dev, 0xdc, 0x01); -- PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); - } - - static void setwhitebalance(struct gspca_dev *gspca_dev) -@@ -597,10 +562,9 @@ static void setwhitebalance(struct gspca - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ -- reg_w(gspca_dev, 0xc6, sd->white_balance); -+ reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val); - - reg_w(gspca_dev, 0xdc, 0x01); -- PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); - } - - static void setredbalance(struct gspca_dev *gspca_dev) -@@ -608,10 +572,9 @@ static void setredbalance(struct gspca_d - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ -- reg_w(gspca_dev, 0xc5, sd->red_balance); -+ reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val); - - reg_w(gspca_dev, 0xdc, 0x01); -- PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); - } - - static void setbluebalance(struct gspca_dev *gspca_dev) -@@ -619,10 +582,9 @@ static void setbluebalance(struct gspca_ - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ -- reg_w(gspca_dev, 0xc7, sd->blue_balance); -+ reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val); - - reg_w(gspca_dev, 0xdc, 0x01); -- PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); - } - - static void setgain(struct gspca_dev *gspca_dev) -@@ -630,7 +592,7 @@ static void setgain(struct gspca_dev *gs - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ -- reg_w(gspca_dev, 0x10, sd->gain >> 3); -+ reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3); - - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); -@@ -639,13 +601,13 @@ static void setgain(struct gspca_dev *gs - static void setexposure(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- __u8 clockdiv; -- __u16 exposure; -+ u8 clockdiv; -+ u16 exposure; - - /* register 2 of frame 3 contains the clock divider configuring the - no fps according to the formula: 90 / reg. sd->exposure is the - desired exposure time in 0.5 ms. */ -- clockdiv = (90 * sd->exposure + 1999) / 2000; -+ clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000; - - /* Note clockdiv = 3 also works, but when running at 30 fps, depending - on the scene being recorded, the camera switches to another -@@ -664,7 +626,7 @@ static void setexposure(struct gspca_dev - - /* frame exposure time in ms = 1000 * clockdiv / 90 -> - exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ -- exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); -+ exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv); - /* 0 = use full frametime, 448 = no exposure, reverse it */ - exposure = 448 - exposure; - -@@ -677,15 +639,35 @@ static void setexposure(struct gspca_dev - reg_w(gspca_dev, 0x11, 0x01); - } - -+static void setautogain(struct gspca_dev *gspca_dev) -+{ -+ struct sd *sd = (struct sd *) gspca_dev; -+ -+ /* when switching to autogain set defaults to make sure -+ we are on a valid point of the autogain gain / -+ exposure knee graph, and give this change time to -+ take effect before doing autogain. */ -+ if (sd->ctrls[AUTOGAIN].val) { -+ sd->ctrls[EXPOSURE].val = EXPOSURE_DEF; -+ sd->ctrls[GAIN].val = GAIN_DEF; -+ sd->autogain_ignore_frames = -+ PAC_AUTOGAIN_IGNORE_FRAMES; -+ } else { -+ sd->autogain_ignore_frames = -1; -+ } -+ setexposure(gspca_dev); -+ setgain(gspca_dev); -+} -+ - static void sethvflip(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; - u8 data, hflip, vflip; - -- hflip = sd->hflip; -+ hflip = sd->ctrls[HFLIP].val; - if (sd->flags & FL_HFLIP) - hflip = !hflip; -- vflip = sd->vflip; -+ vflip = sd->ctrls[VFLIP].val; - if (sd->flags & FL_VFLIP) - vflip = !vflip; - -@@ -708,8 +690,6 @@ static int sd_start(struct gspca_dev *gs - { - struct sd *sd = (struct sd *) gspca_dev; - -- sd->sof_read = 0; -- - reg_w_var(gspca_dev, start_7302, - page3_7302, sizeof(page3_7302)); - setbrightcont(gspca_dev); -@@ -717,15 +697,13 @@ static int sd_start(struct gspca_dev *gs - setwhitebalance(gspca_dev); - setredbalance(gspca_dev); - setbluebalance(gspca_dev); -- setgain(gspca_dev); -- setexposure(gspca_dev); -+ setautogain(gspca_dev); - sethvflip(gspca_dev); - - /* only resolution 640x480 is supported for pac7302 */ - - sd->sof_read = 0; -- sd->autogain_ignore_frames = 0; -- atomic_set(&sd->avg_lum, -1); -+ atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val); - - /* start stream */ - reg_w(gspca_dev, 0xff, 0x01); -@@ -751,8 +729,10 @@ static void sd_stop0(struct gspca_dev *g - reg_w(gspca_dev, 0x78, 0x40); - } - --/* Include pac common sof detection functions */ --#include "pac_common.h" -+/* !! coarse_grained_expo_autogain is not used !! */ -+#define exp_too_low_cnt flags -+#define exp_too_high_cnt sof_read -+#include "autogain_functions.h" - - static void do_autogain(struct gspca_dev *gspca_dev) - { -@@ -761,65 +741,44 @@ static void do_autogain(struct gspca_dev - int desired_lum; - const int deadzone = 30; - -- if (avg_lum == -1) -+ if (sd->autogain_ignore_frames < 0) - return; - -- desired_lum = 270 + sd->brightness; -- -- if (sd->autogain_ignore_frames > 0) -+ if (sd->autogain_ignore_frames > 0) { - sd->autogain_ignore_frames--; -- else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, -- deadzone, GAIN_KNEE, EXPOSURE_KNEE)) -+ } else { -+ desired_lum = 270 + sd->ctrls[BRIGHTNESS].val; -+ -+ auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, -+ deadzone, GAIN_KNEE, EXPOSURE_KNEE); - sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; -+ } - } - --/* JPEG header, part 1 */ --static const unsigned char pac_jpeg_header1[] = { -- 0xff, 0xd8, /* SOI: Start of Image */ -- -- 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ -- 0x00, 0x11, /* length = 17 bytes (including this length field) */ -- 0x08 /* Precision: 8 */ -- /* 2 bytes is placed here: number of image lines */ -- /* 2 bytes is placed here: samples per line */ --}; -- --/* JPEG header, continued */ --static const unsigned char pac_jpeg_header2[] = { -- 0x03, /* Number of image components: 3 */ -- 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ -- 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ -- 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ -- -- 0xff, 0xda, /* SOS: Start Of Scan */ -- 0x00, 0x0c, /* length = 12 bytes (including this length field) */ -- 0x03, /* number of components: 3 */ -- 0x01, 0x00, /* selector 1, table 0x00 */ -- 0x02, 0x11, /* selector 2, table 0x11 */ -- 0x03, 0x11, /* selector 3, table 0x11 */ -- 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ -- 0x00 /* Successive approximation: 0 */ -+/* JPEG header */ -+static const u8 jpeg_header[] = { -+ 0xff, 0xd8, /* SOI: Start of Image */ -+ -+ 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */ -+ 0x00, 0x11, /* length = 17 bytes (including this length field) */ -+ 0x08, /* Precision: 8 */ -+ 0x02, 0x80, /* height = 640 (image rotated) */ -+ 0x01, 0xe0, /* width = 480 */ -+ 0x03, /* Number of image components: 3 */ -+ 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */ -+ 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */ -+ 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */ -+ -+ 0xff, 0xda, /* SOS: Start Of Scan */ -+ 0x00, 0x0c, /* length = 12 bytes (including this length field) */ -+ 0x03, /* number of components: 3 */ -+ 0x01, 0x00, /* selector 1, table 0x00 */ -+ 0x02, 0x11, /* selector 2, table 0x11 */ -+ 0x03, 0x11, /* selector 3, table 0x11 */ -+ 0x00, 0x3f, /* Spectral selection: 0 .. 63 */ -+ 0x00 /* Successive approximation: 0 */ - }; - --static void pac_start_frame(struct gspca_dev *gspca_dev, -- __u16 lines, __u16 samples_per_line) --{ -- unsigned char tmpbuf[4]; -- -- gspca_frame_add(gspca_dev, FIRST_PACKET, -- pac_jpeg_header1, sizeof(pac_jpeg_header1)); -- -- tmpbuf[0] = lines >> 8; -- tmpbuf[1] = lines & 0xff; -- tmpbuf[2] = samples_per_line >> 8; -- tmpbuf[3] = samples_per_line & 0xff; -- -- gspca_frame_add(gspca_dev, INTER_PACKET, -- tmpbuf, sizeof(tmpbuf)); -- gspca_frame_add(gspca_dev, INTER_PACKET, -- pac_jpeg_header2, sizeof(pac_jpeg_header2)); --} -- - /* this function is run at interrupt level */ - static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ -@@ -827,7 +786,7 @@ static void sd_pkt_scan(struct gspca_dev - { - struct sd *sd = (struct sd *) gspca_dev; - u8 *image; -- unsigned char *sof; -+ u8 *sof; - - sof = pac_find_sof(&sd->sof_read, data, len); - if (sof) { -@@ -864,234 +823,21 @@ static void sd_pkt_scan(struct gspca_dev - n >= lum_offset) - atomic_set(&sd->avg_lum, data[-lum_offset] + - data[-lum_offset + 1]); -- else -- atomic_set(&sd->avg_lum, -1); - - /* Start the new frame with the jpeg header */ - /* The PAC7302 has the image rotated 90 degrees */ -- pac_start_frame(gspca_dev, -- gspca_dev->width, gspca_dev->height); -+ gspca_frame_add(gspca_dev, FIRST_PACKET, -+ jpeg_header, sizeof jpeg_header); - } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - } - --static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->brightness = val; -- if (gspca_dev->streaming) -- setbrightcont(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->brightness; -- return 0; --} -- --static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->contrast = val; -- if (gspca_dev->streaming) -- setbrightcont(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->contrast; -- return 0; --} -- --static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->colors = val; -- if (gspca_dev->streaming) -- setcolors(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->colors; -- return 0; --} -- --static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->white_balance = val; -- if (gspca_dev->streaming) -- setwhitebalance(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->white_balance; -- return 0; --} -- --static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->red_balance = val; -- if (gspca_dev->streaming) -- setredbalance(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->red_balance; -- return 0; --} -- --static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->blue_balance = val; -- if (gspca_dev->streaming) -- setbluebalance(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->blue_balance; -- return 0; --} -- --static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->gain = val; -- if (gspca_dev->streaming) -- setgain(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->gain; -- return 0; --} -- --static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->exposure = val; -- if (gspca_dev->streaming) -- setexposure(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->exposure; -- return 0; --} -- --static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->autogain = val; -- /* when switching to autogain set defaults to make sure -- we are on a valid point of the autogain gain / -- exposure knee graph, and give this change time to -- take effect before doing autogain. */ -- if (sd->autogain) { -- sd->exposure = EXPOSURE_DEF; -- sd->gain = GAIN_DEF; -- if (gspca_dev->streaming) { -- sd->autogain_ignore_frames = -- PAC_AUTOGAIN_IGNORE_FRAMES; -- setexposure(gspca_dev); -- setgain(gspca_dev); -- } -- } -- -- return gspca_dev->usb_err; --} -- --static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->autogain; -- return 0; --} -- --static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->hflip = val; -- if (gspca_dev->streaming) -- sethvflip(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->hflip; -- return 0; --} -- --static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->vflip = val; -- if (gspca_dev->streaming) -- sethvflip(gspca_dev); -- return gspca_dev->usb_err; --} -- --static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- *val = sd->vflip; -- return 0; --} -- - #ifdef CONFIG_VIDEO_ADV_DEBUG - static int sd_dbg_s_register(struct gspca_dev *gspca_dev, - struct v4l2_dbg_register *reg) - { -- __u8 index; -- __u8 value; -+ u8 index; -+ u8 value; - - /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit - long on the USB bus) -@@ -1103,8 +849,8 @@ static int sd_dbg_s_register(struct gspc - ) { - /* Currently writing to page 0 is only supported. */ - /* reg_w() only supports 8bit index */ -- index = reg->reg & 0x000000ff; -- value = reg->val & 0x000000ff; -+ index = reg->reg; -+ value = reg->val; - - /* Note that there shall be no access to other page - by any other function between the page swith and -@@ -1165,7 +911,7 @@ static int sd_int_pkt_scan(struct gspca_ - - /* sub-driver description for pac7302 */ - static const struct sd_desc sd_desc = { -- .name = MODULE_NAME, -+ .name = KBUILD_MODNAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, -@@ -1187,6 +933,7 @@ static const struct sd_desc sd_desc = { - /* -- module initialisation -- */ - static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x06f8, 0x3009)}, -+ {USB_DEVICE(0x06f8, 0x301b)}, - {USB_DEVICE(0x093a, 0x2620)}, - {USB_DEVICE(0x093a, 0x2621)}, - {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, -@@ -1211,7 +958,7 @@ static int sd_probe(struct usb_interface - } - - static struct usb_driver sd_driver = { -- .name = MODULE_NAME, -+ .name = KBUILD_MODNAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -Index: linux-3.3.x86_64/drivers/media/video/gspca/sonixj.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/gspca/sonixj.c -+++ linux-3.3.x86_64/drivers/media/video/gspca/sonixj.c -@@ -39,7 +39,9 @@ enum e_ctrl { - BLUE, - RED, - GAMMA, -+ EXPOSURE, - AUTOGAIN, -+ GAIN, - HFLIP, - VFLIP, - SHARPNESS, -@@ -131,7 +133,9 @@ static void setcontrast(struct gspca_dev - static void setcolors(struct gspca_dev *gspca_dev); - static void setredblue(struct gspca_dev *gspca_dev); - static void setgamma(struct gspca_dev *gspca_dev); --static void setautogain(struct gspca_dev *gspca_dev); -+static void setexposure(struct gspca_dev *gspca_dev); -+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -+static void setgain(struct gspca_dev *gspca_dev); - static void sethvflip(struct gspca_dev *gspca_dev); - static void setsharpness(struct gspca_dev *gspca_dev); - static void setillum(struct gspca_dev *gspca_dev); -@@ -213,6 +217,18 @@ static const struct ctrl sd_ctrls[NCTRLS - }, - .set_control = setgamma - }, -+[EXPOSURE] = { -+ { -+ .id = V4L2_CID_EXPOSURE, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Exposure", -+ .minimum = 500, -+ .maximum = 1500, -+ .step = 1, -+ .default_value = 1024 -+ }, -+ .set_control = setexposure -+ }, - [AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, -@@ -223,7 +239,19 @@ static const struct ctrl sd_ctrls[NCTRLS - .step = 1, - .default_value = 1 - }, -- .set_control = setautogain -+ .set = sd_setautogain, -+ }, -+[GAIN] = { -+ { -+ .id = V4L2_CID_GAIN, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Gain", -+ .minimum = 4, -+ .maximum = 49, -+ .step = 1, -+ .default_value = 15 -+ }, -+ .set_control = setgain - }, - [HFLIP] = { - { -@@ -290,60 +318,87 @@ static const struct ctrl sd_ctrls[NCTRLS - - /* table of the disabled controls */ - static const __u32 ctrl_dis[] = { --[SENSOR_ADCM1700] = (1 << AUTOGAIN) | -+[SENSOR_ADCM1700] = (1 << EXPOSURE) | -+ (1 << AUTOGAIN) | -+ (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_GC0307] = (1 << HFLIP) | -+[SENSOR_GC0307] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_HV7131R] = (1 << HFLIP) | -+[SENSOR_HV7131R] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP) | - (1 << FREQ), - --[SENSOR_MI0360] = (1 << HFLIP) | -+[SENSOR_MI0360] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_MI0360B] = (1 << HFLIP) | -+[SENSOR_MI0360B] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_MO4000] = (1 << HFLIP) | -+[SENSOR_MO4000] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_MT9V111] = (1 << HFLIP) | -+[SENSOR_MT9V111] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_OM6802] = (1 << HFLIP) | -+[SENSOR_OM6802] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_OV7630] = (1 << HFLIP), -- --[SENSOR_OV7648] = (1 << HFLIP), -- --[SENSOR_OV7660] = (1 << AUTOGAIN) | -+[SENSOR_OV7630] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP), -+ -+[SENSOR_OV7648] = (1 << EXPOSURE) | -+ (1 << GAIN) | -+ (1 << HFLIP), -+ -+[SENSOR_OV7660] = (1 << EXPOSURE) | -+ (1 << AUTOGAIN) | -+ (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP), - --[SENSOR_PO1030] = (1 << AUTOGAIN) | -+[SENSOR_PO1030] = (1 << EXPOSURE) | -+ (1 << AUTOGAIN) | -+ (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_PO2030N] = (1 << AUTOGAIN) | -- (1 << FREQ), -+[SENSOR_PO2030N] = (1 << FREQ), - --[SENSOR_SOI768] = (1 << AUTOGAIN) | -+[SENSOR_SOI768] = (1 << EXPOSURE) | -+ (1 << AUTOGAIN) | -+ (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - --[SENSOR_SP80708] = (1 << AUTOGAIN) | -+[SENSOR_SP80708] = (1 << EXPOSURE) | -+ (1 << AUTOGAIN) | -+ (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), -@@ -1242,14 +1297,6 @@ static const u8 po2030n_sensor_param1[][ - {0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10}, -- {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, -- {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10}, --/*after start*/ -- {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10}, -- {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ -- {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10}, -- {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */ -- {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10}, - {} - }; - -@@ -1858,7 +1905,7 @@ static int sd_init(struct gspca_dev *gsp - return gspca_dev->usb_err; - } - --static u32 setexposure(struct gspca_dev *gspca_dev, -+static u32 expo_adjust(struct gspca_dev *gspca_dev, - u32 expo) - { - struct sd *sd = (struct sd *) gspca_dev; -@@ -1982,28 +2029,28 @@ static void setbrightness(struct gspca_d - expo = 0x002dc6c0; - else if (expo < 0x02a0) - expo = 0x02a0; -- sd->exposure = setexposure(gspca_dev, expo); -+ sd->exposure = expo_adjust(gspca_dev, expo); - break; - case SENSOR_MI0360: - case SENSOR_MO4000: - expo = brightness << 4; -- sd->exposure = setexposure(gspca_dev, expo); -+ sd->exposure = expo_adjust(gspca_dev, expo); - break; - case SENSOR_MI0360B: - expo = brightness << 2; -- sd->exposure = setexposure(gspca_dev, expo); -+ sd->exposure = expo_adjust(gspca_dev, expo); - break; - case SENSOR_GC0307: - expo = brightness; -- sd->exposure = setexposure(gspca_dev, expo); -+ sd->exposure = expo_adjust(gspca_dev, expo); - return; /* don't set the Y offset */ - case SENSOR_MT9V111: - expo = brightness << 2; -- sd->exposure = setexposure(gspca_dev, expo); -+ sd->exposure = expo_adjust(gspca_dev, expo); - return; /* don't set the Y offset */ - case SENSOR_OM6802: - expo = brightness << 2; -- sd->exposure = setexposure(gspca_dev, expo); -+ sd->exposure = expo_adjust(gspca_dev, expo); - return; /* Y offset already set */ - } - -@@ -2112,6 +2159,23 @@ static void setgamma(struct gspca_dev *g - reg_w(gspca_dev, 0x20, gamma, sizeof gamma); - } - -+static void setexposure(struct gspca_dev *gspca_dev) -+{ -+ struct sd *sd = (struct sd *) gspca_dev; -+ -+ if (sd->sensor == SENSOR_PO2030N) { -+ u8 rexpo[] = /* 1a: expo H, 1b: expo M */ -+ {0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10}; -+ -+ rexpo[3] = sd->ctrls[EXPOSURE].val >> 8; -+ i2c_w8(gspca_dev, rexpo); -+ msleep(6); -+ rexpo[2] = 0x1b; -+ rexpo[3] = sd->ctrls[EXPOSURE].val; -+ i2c_w8(gspca_dev, rexpo); -+ } -+} -+ - static void setautogain(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -@@ -2139,6 +2203,19 @@ static void setautogain(struct gspca_dev - sd->ag_cnt = -1; - } - -+static void setgain(struct gspca_dev *gspca_dev) -+{ -+ struct sd *sd = (struct sd *) gspca_dev; -+ -+ if (sd->sensor == SENSOR_PO2030N) { -+ u8 rgain[] = /* 15: gain */ -+ {0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15}; -+ -+ rgain[3] = sd->ctrls[GAIN].val; -+ i2c_w8(gspca_dev, rgain); -+ } -+} -+ - static void sethvflip(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -@@ -2623,6 +2700,10 @@ static int sd_start(struct gspca_dev *gs - setcontrast(gspca_dev); - setcolors(gspca_dev); - setautogain(gspca_dev); -+ if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) { -+ setexposure(gspca_dev); -+ setgain(gspca_dev); -+ } - setfreq(gspca_dev); - - sd->pktsz = sd->npkt = 0; -@@ -2719,6 +2800,12 @@ static void sd_stop0(struct gspca_dev *g - } - } - -+/* !! coarse_grained_expo_autogain is not used !! */ -+#define exp_too_low_cnt bridge -+#define exp_too_high_cnt sensor -+ -+#include "autogain_functions.h" -+ - static void do_autogain(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -@@ -2736,6 +2823,13 @@ static void do_autogain(struct gspca_dev - - delta = atomic_read(&sd->avg_lum); - PDEBUG(D_FRAM, "mean lum %d", delta); -+ -+ if (sd->sensor == SENSOR_PO2030N) { -+ auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta, -+ 15, 1024); -+ return; -+ } -+ - if (delta < luma_mean - luma_delta || - delta > luma_mean + luma_delta) { - switch (sd->sensor) { -@@ -2744,7 +2838,7 @@ static void do_autogain(struct gspca_dev - expotimes += (luma_mean - delta) >> 6; - if (expotimes < 0) - expotimes = 0; -- sd->exposure = setexposure(gspca_dev, -+ sd->exposure = expo_adjust(gspca_dev, - (unsigned int) expotimes); - break; - case SENSOR_HV7131R: -@@ -2752,7 +2846,7 @@ static void do_autogain(struct gspca_dev - expotimes += (luma_mean - delta) >> 4; - if (expotimes < 0) - expotimes = 0; -- sd->exposure = setexposure(gspca_dev, -+ sd->exposure = expo_adjust(gspca_dev, - (unsigned int) (expotimes << 8)); - break; - case SENSOR_OM6802: -@@ -2761,7 +2855,7 @@ static void do_autogain(struct gspca_dev - expotimes += (luma_mean - delta) >> 2; - if (expotimes < 0) - expotimes = 0; -- sd->exposure = setexposure(gspca_dev, -+ sd->exposure = expo_adjust(gspca_dev, - (unsigned int) expotimes); - setredblue(gspca_dev); - break; -@@ -2773,7 +2867,7 @@ static void do_autogain(struct gspca_dev - expotimes += (luma_mean - delta) >> 6; - if (expotimes < 0) - expotimes = 0; -- sd->exposure = setexposure(gspca_dev, -+ sd->exposure = expo_adjust(gspca_dev, - (unsigned int) expotimes); - setredblue(gspca_dev); - break; -@@ -2948,16 +3042,18 @@ marker_found: - } - } - --static int sd_get_jcomp(struct gspca_dev *gspca_dev, -- struct v4l2_jpegcompression *jcomp) -+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) - { - struct sd *sd = (struct sd *) gspca_dev; - -- memset(jcomp, 0, sizeof *jcomp); -- jcomp->quality = sd->quality; -- jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT -- | V4L2_JPEG_MARKER_DQT; -- return 0; -+ sd->ctrls[AUTOGAIN].val = val; -+ if (val) -+ gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); -+ else -+ gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN); -+ if (gspca_dev->streaming) -+ setautogain(gspca_dev); -+ return gspca_dev->usb_err; - } - - static int sd_querymenu(struct gspca_dev *gspca_dev, -@@ -3012,7 +3108,6 @@ static const struct sd_desc sd_desc = { - .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - .dq_callback = do_autogain, -- .get_jcomp = sd_get_jcomp, - .querymenu = sd_querymenu, - #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -Index: linux-3.3.x86_64/drivers/media/video/gspca/zc3xx.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/gspca/zc3xx.c -+++ linux-3.3.x86_64/drivers/media/video/gspca/zc3xx.c -@@ -1,7 +1,7 @@ - /* -- * Z-Star/Vimicro zc301/zc302p/vc30x library -+ * Z-Star/Vimicro zc301/zc302p/vc30x driver - * -- * Copyright (C) 2009-2011 Jean-Francois Moine -+ * Copyright (C) 2009-2012 Jean-Francois Moine - * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr - * - * This program is free software; you can redistribute it and/or modify -@@ -21,8 +21,6 @@ - - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - --#define MODULE_NAME "zc3xx" -- - #include - #include "gspca.h" - #include "jpeg.h" -@@ -34,7 +32,7 @@ MODULE_LICENSE("GPL"); - - static int force_sensor = -1; - --#define QUANT_VAL 1 /* quantization table */ -+#define REG08_DEF 3 /* default JPEG compression (70%) */ - #include "zc3xx-reg.h" - - /* controls */ -@@ -46,6 +44,7 @@ enum e_ctrl { - AUTOGAIN, - LIGHTFREQ, - SHARPNESS, -+ QUALITY, - NCTRLS /* number of controls */ - }; - -@@ -57,10 +56,10 @@ struct sd { - - struct gspca_ctrl ctrls[NCTRLS]; - -- u8 quality; /* image quality */ --#define QUALITY_MIN 50 --#define QUALITY_MAX 80 --#define QUALITY_DEF 70 -+ struct work_struct work; -+ struct workqueue_struct *work_thread; -+ -+ u8 reg08; /* webcam compression quality */ - - u8 bridge; - u8 sensor; /* Type of image sensor chip */ -@@ -101,6 +100,7 @@ static void setexposure(struct gspca_dev - static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); - static void setlightfreq(struct gspca_dev *gspca_dev); - static void setsharpness(struct gspca_dev *gspca_dev); -+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val); - - static const struct ctrl sd_ctrls[NCTRLS] = { - [BRIGHTNESS] = { -@@ -188,6 +188,18 @@ static const struct ctrl sd_ctrls[NCTRLS - }, - .set_control = setsharpness - }, -+[QUALITY] = { -+ { -+ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Compression Quality", -+ .minimum = 40, -+ .maximum = 70, -+ .step = 1, -+ .default_value = 70 /* updated in sd_init() */ -+ }, -+ .set = sd_setquality -+ }, - }; - - static const struct v4l2_pix_format vga_mode[] = { -@@ -229,6 +241,9 @@ static const struct v4l2_pix_format sif_ - .priv = 0}, - }; - -+/* bridge reg08 -> JPEG quality conversion table */ -+static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/}; -+ - /* usb exchanges */ - struct usb_action { - u8 req; -@@ -3894,7 +3909,6 @@ static const struct usb_action pas106b_I - /* Gains */ - {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP}, -- {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - /* Auto correction */ - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, -@@ -5640,7 +5654,7 @@ static const struct usb_action gc0303_No - {} - }; - --static u8 reg_r_i(struct gspca_dev *gspca_dev, -+static u8 reg_r(struct gspca_dev *gspca_dev, - u16 index) - { - int ret; -@@ -5655,24 +5669,14 @@ static u8 reg_r_i(struct gspca_dev *gspc - index, gspca_dev->usb_buf, 1, - 500); - if (ret < 0) { -- pr_err("reg_r_i err %d\n", ret); -+ pr_err("reg_r err %d\n", ret); - gspca_dev->usb_err = ret; - return 0; - } - return gspca_dev->usb_buf[0]; - } - --static u8 reg_r(struct gspca_dev *gspca_dev, -- u16 index) --{ -- u8 ret; -- -- ret = reg_r_i(gspca_dev, index); -- PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret); -- return ret; --} -- --static void reg_w_i(struct gspca_dev *gspca_dev, -+static void reg_w(struct gspca_dev *gspca_dev, - u8 value, - u16 index) - { -@@ -5692,14 +5696,6 @@ static void reg_w_i(struct gspca_dev *gs - } - } - --static void reg_w(struct gspca_dev *gspca_dev, -- u8 value, -- u16 index) --{ -- PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value); -- reg_w_i(gspca_dev, value, index); --} -- - static u16 i2c_read(struct gspca_dev *gspca_dev, - u8 reg) - { -@@ -5708,16 +5704,14 @@ static u16 i2c_read(struct gspca_dev *gs - - if (gspca_dev->usb_err < 0) - return 0; -- reg_w_i(gspca_dev, reg, 0x0092); -- reg_w_i(gspca_dev, 0x02, 0x0090); /* <- read command */ -+ reg_w(gspca_dev, reg, 0x0092); -+ reg_w(gspca_dev, 0x02, 0x0090); /* <- read command */ - msleep(20); -- retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ -+ retbyte = reg_r(gspca_dev, 0x0091); /* read status */ - if (retbyte != 0x00) - pr_err("i2c_r status error %02x\n", retbyte); -- retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */ -- retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */ -- PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)", -- reg, retval, retbyte); -+ retval = reg_r(gspca_dev, 0x0095); /* read Lowbyte */ -+ retval |= reg_r(gspca_dev, 0x0096) << 8; /* read Hightbyte */ - return retval; - } - -@@ -5730,16 +5724,14 @@ static u8 i2c_write(struct gspca_dev *gs - - if (gspca_dev->usb_err < 0) - return 0; -- reg_w_i(gspca_dev, reg, 0x92); -- reg_w_i(gspca_dev, valL, 0x93); -- reg_w_i(gspca_dev, valH, 0x94); -- reg_w_i(gspca_dev, 0x01, 0x90); /* <- write command */ -+ reg_w(gspca_dev, reg, 0x92); -+ reg_w(gspca_dev, valL, 0x93); -+ reg_w(gspca_dev, valH, 0x94); -+ reg_w(gspca_dev, 0x01, 0x90); /* <- write command */ - msleep(1); -- retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ -+ retbyte = reg_r(gspca_dev, 0x0091); /* read status */ - if (retbyte != 0x00) - pr_err("i2c_w status error %02x\n", retbyte); -- PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", -- reg, valH, valL, retbyte); - return retbyte; - } - -@@ -5906,6 +5898,8 @@ static void getexposure(struct gspca_dev - { - struct sd *sd = (struct sd *) gspca_dev; - -+ if (sd->sensor != SENSOR_HV7131R) -+ return; - sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9) - | (i2c_read(gspca_dev, 0x26) << 1) - | (i2c_read(gspca_dev, 0x27) >> 7); -@@ -5916,6 +5910,8 @@ static void setexposure(struct gspca_dev - struct sd *sd = (struct sd *) gspca_dev; - int val; - -+ if (sd->sensor != SENSOR_HV7131R) -+ return; - val = sd->ctrls[EXPOSURE].val; - i2c_write(gspca_dev, 0x25, val >> 9, 0x00); - i2c_write(gspca_dev, 0x26, val >> 1, 0x00); -@@ -5925,32 +5921,20 @@ static void setexposure(struct gspca_dev - static void setquality(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- u8 frxt; -+ s8 reg07; - -+ reg07 = 0; - switch (sd->sensor) { -- case SENSOR_ADCM2700: -- case SENSOR_GC0305: -- case SENSOR_HV7131B: -- case SENSOR_HV7131R: - case SENSOR_OV7620: -+ reg07 = 0x30; -+ break; -+ case SENSOR_HV7131R: - case SENSOR_PAS202B: -- case SENSOR_PO2030: -- return; -+ return; /* done by work queue */ - } --/*fixme: is it really 0008 0007 0018 for all other sensors? */ -- reg_w(gspca_dev, QUANT_VAL, 0x0008); -- frxt = 0x30; -- reg_w(gspca_dev, frxt, 0x0007); --#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2 -- frxt = 0xff; --#elif QUANT_VAL == 3 -- frxt = 0xf0; --#elif QUANT_VAL == 4 -- frxt = 0xe0; --#else -- frxt = 0x20; --#endif -- reg_w(gspca_dev, frxt, 0x0018); -+ reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); -+ if (reg07 != 0) -+ reg_w(gspca_dev, reg07, 0x0007); - } - - /* Matches the sensor's internal frame rate to the lighting frequency. -@@ -6084,6 +6068,115 @@ static void setautogain(struct gspca_dev - reg_w(gspca_dev, autoval, 0x0180); - } - -+/* update the transfer parameters */ -+/* This function is executed from a work queue. */ -+/* The exact use of the bridge registers 07 and 08 is not known. -+ * The following algorithm has been adapted from ms-win traces */ -+static void transfer_update(struct work_struct *work) -+{ -+ struct sd *sd = container_of(work, struct sd, work); -+ struct gspca_dev *gspca_dev = &sd->gspca_dev; -+ int change, good; -+ u8 reg07, reg11; -+ -+ /* synchronize with the main driver and initialize the registers */ -+ mutex_lock(&gspca_dev->usb_lock); -+ reg07 = 0; /* max */ -+ reg_w(gspca_dev, reg07, 0x0007); -+ reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); -+ mutex_unlock(&gspca_dev->usb_lock); -+ -+ good = 0; -+ for (;;) { -+ msleep(100); -+ -+ /* get the transfer status */ -+ /* the bit 0 of the bridge register 11 indicates overflow */ -+ mutex_lock(&gspca_dev->usb_lock); -+ if (!gspca_dev->present || !gspca_dev->streaming) -+ goto err; -+ reg11 = reg_r(gspca_dev, 0x0011); -+ if (gspca_dev->usb_err < 0 -+ || !gspca_dev->present || !gspca_dev->streaming) -+ goto err; -+ -+ change = reg11 & 0x01; -+ if (change) { /* overflow */ -+ switch (reg07) { -+ case 0: /* max */ -+ reg07 = sd->sensor == SENSOR_HV7131R -+ ? 0x30 : 0x32; -+ if (sd->reg08 != 0) { -+ change = 3; -+ sd->reg08--; -+ } -+ break; -+ case 0x32: -+ reg07 -= 4; -+ break; -+ default: -+ reg07 -= 2; -+ break; -+ case 2: -+ change = 0; /* already min */ -+ break; -+ } -+ good = 0; -+ } else { /* no overflow */ -+ if (reg07 != 0) { /* if not max */ -+ good++; -+ if (good >= 10) { -+ good = 0; -+ change = 1; -+ reg07 += 2; -+ switch (reg07) { -+ case 0x30: -+ if (sd->sensor == SENSOR_PAS202B) -+ reg07 += 2; -+ break; -+ case 0x32: -+ case 0x34: -+ reg07 = 0; -+ break; -+ } -+ } -+ } else { /* reg07 max */ -+ if (sd->reg08 < sizeof jpeg_qual - 1) { -+ good++; -+ if (good > 10) { -+ sd->reg08++; -+ change = 2; -+ } -+ } -+ } -+ } -+ if (change) { -+ if (change & 1) { -+ reg_w(gspca_dev, reg07, 0x0007); -+ if (gspca_dev->usb_err < 0 -+ || !gspca_dev->present -+ || !gspca_dev->streaming) -+ goto err; -+ } -+ if (change & 2) { -+ reg_w(gspca_dev, sd->reg08, -+ ZC3XX_R008_CLOCKSETTING); -+ if (gspca_dev->usb_err < 0 -+ || !gspca_dev->present -+ || !gspca_dev->streaming) -+ goto err; -+ sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08]; -+ jpeg_set_qual(sd->jpeg_hdr, -+ jpeg_qual[sd->reg08]); -+ } -+ } -+ mutex_unlock(&gspca_dev->usb_lock); -+ } -+ return; -+err: -+ mutex_unlock(&gspca_dev->usb_lock); -+} -+ - static void send_unknown(struct gspca_dev *gspca_dev, int sensor) - { - reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */ -@@ -6411,7 +6504,9 @@ static int sd_config(struct gspca_dev *g - sd->sensor = id->driver_info; - - gspca_dev->cam.ctrls = sd->ctrls; -- sd->quality = QUALITY_DEF; -+ sd->reg08 = REG08_DEF; -+ -+ INIT_WORK(&sd->work, transfer_update); - - return 0; - } -@@ -6464,6 +6559,27 @@ static int sd_init(struct gspca_dev *gsp - [SENSOR_PO2030] = 1, - [SENSOR_TAS5130C] = 1, - }; -+ static const u8 reg08_tb[SENSOR_MAX] = { -+ [SENSOR_ADCM2700] = 1, -+ [SENSOR_CS2102] = 3, -+ [SENSOR_CS2102K] = 3, -+ [SENSOR_GC0303] = 2, -+ [SENSOR_GC0305] = 3, -+ [SENSOR_HDCS2020] = 1, -+ [SENSOR_HV7131B] = 3, -+ [SENSOR_HV7131R] = 3, -+ [SENSOR_ICM105A] = 3, -+ [SENSOR_MC501CB] = 3, -+ [SENSOR_MT9V111_1] = 3, -+ [SENSOR_MT9V111_3] = 3, -+ [SENSOR_OV7620] = 1, -+ [SENSOR_OV7630C] = 3, -+ [SENSOR_PAS106] = 3, -+ [SENSOR_PAS202B] = 3, -+ [SENSOR_PB0330] = 3, -+ [SENSOR_PO2030] = 2, -+ [SENSOR_TAS5130C] = 3, -+ }; - - sensor = zcxx_probeSensor(gspca_dev); - if (sensor >= 0) -@@ -6528,7 +6644,6 @@ static int sd_init(struct gspca_dev *gsp - case 0x0e: - PDEBUG(D_PROBE, "Find Sensor PAS202B"); - sd->sensor = SENSOR_PAS202B; --/* sd->sharpness = 1; */ - break; - case 0x0f: - PDEBUG(D_PROBE, "Find Sensor PAS106"); -@@ -6616,13 +6731,21 @@ static int sd_init(struct gspca_dev *gsp - } - - sd->ctrls[GAMMA].def = gamma[sd->sensor]; -+ sd->reg08 = reg08_tb[sd->sensor]; -+ sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08]; -+ sd->ctrls[QUALITY].min = jpeg_qual[0]; -+ sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1]; - - switch (sd->sensor) { - case SENSOR_HV7131R: -+ gspca_dev->ctrl_dis = (1 << QUALITY); - break; - case SENSOR_OV7630C: - gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); - break; -+ case SENSOR_PAS202B: -+ gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE); -+ break; - default: - gspca_dev->ctrl_dis = (1 << EXPOSURE); - break; -@@ -6685,7 +6808,6 @@ static int sd_start(struct gspca_dev *gs - /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, - 0x21); /* JPEG 422 */ -- jpeg_set_qual(sd->jpeg_hdr, sd->quality); - - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - switch (sd->sensor) { -@@ -6761,10 +6883,9 @@ static int sd_start(struct gspca_dev *gs - reg_r(gspca_dev, 0x0180); /* from win */ - reg_w(gspca_dev, 0x00, 0x0180); - break; -- default: -- setquality(gspca_dev); -- break; - } -+ setquality(gspca_dev); -+ jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]); - setlightfreq(gspca_dev); - - switch (sd->sensor) { -@@ -6776,8 +6897,7 @@ static int sd_start(struct gspca_dev *gs - reg_w(gspca_dev, 0x40, 0x0117); - break; - case SENSOR_HV7131R: -- if (!sd->ctrls[AUTOGAIN].val) -- setexposure(gspca_dev); -+ setexposure(gspca_dev); - reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); - break; - case SENSOR_GC0305: -@@ -6802,13 +6922,19 @@ static int sd_start(struct gspca_dev *gs - } - - setautogain(gspca_dev); -- switch (sd->sensor) { -- case SENSOR_PO2030: -- msleep(50); -- reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */ -- reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING); -- break; -+ -+ /* start the transfer update thread if needed */ -+ if (gspca_dev->usb_err >= 0) { -+ switch (sd->sensor) { -+ case SENSOR_HV7131R: -+ case SENSOR_PAS202B: -+ sd->work_thread = -+ create_singlethread_workqueue(KBUILD_MODNAME); -+ queue_work(sd->work_thread, &sd->work); -+ break; -+ } - } -+ - return gspca_dev->usb_err; - } - -@@ -6817,6 +6943,12 @@ static void sd_stop0(struct gspca_dev *g - { - struct sd *sd = (struct sd *) gspca_dev; - -+ if (sd->work_thread != NULL) { -+ mutex_unlock(&gspca_dev->usb_lock); -+ destroy_workqueue(sd->work_thread); -+ mutex_lock(&gspca_dev->usb_lock); -+ sd->work_thread = NULL; -+ } - if (!gspca_dev->present) - return; - send_unknown(gspca_dev, sd->sensor); -@@ -6893,19 +7025,33 @@ static int sd_querymenu(struct gspca_dev - return -EINVAL; - } - -+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val) -+{ -+ struct sd *sd = (struct sd *) gspca_dev; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) { -+ if (val <= jpeg_qual[i]) -+ break; -+ } -+ if (i > 0 -+ && i == sd->reg08 -+ && val < jpeg_qual[sd->reg08]) -+ i--; -+ sd->reg08 = i; -+ sd->ctrls[QUALITY].val = jpeg_qual[i]; -+ if (gspca_dev->streaming) -+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); -+ return gspca_dev->usb_err; -+} -+ - static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) - { - struct sd *sd = (struct sd *) gspca_dev; - -- if (jcomp->quality < QUALITY_MIN) -- sd->quality = QUALITY_MIN; -- else if (jcomp->quality > QUALITY_MAX) -- sd->quality = QUALITY_MAX; -- else -- sd->quality = jcomp->quality; -- if (gspca_dev->streaming) -- jpeg_set_qual(sd->jpeg_hdr, sd->quality); -+ sd_setquality(gspca_dev, jcomp->quality); -+ jcomp->quality = sd->ctrls[QUALITY].val; - return gspca_dev->usb_err; - } - -@@ -6915,7 +7061,7 @@ static int sd_get_jcomp(struct gspca_dev - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); -- jcomp->quality = sd->quality; -+ jcomp->quality = sd->ctrls[QUALITY].val; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -@@ -6938,7 +7084,7 @@ static int sd_int_pkt_scan(struct gspca_ - #endif - - static const struct sd_desc sd_desc = { -- .name = MODULE_NAME, -+ .name = KBUILD_MODNAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, -@@ -7023,7 +7169,7 @@ static int sd_probe(struct usb_interface - - /* USB driver */ - static struct usb_driver sd_driver = { -- .name = MODULE_NAME, -+ .name = KBUILD_MODNAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/au8522_decoder.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/au8522_decoder.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/au8522_decoder.c -@@ -839,15 +839,4 @@ static struct i2c_driver au8522_driver = - .id_table = au8522_id, - }; - --static __init int init_au8522(void) --{ -- return i2c_add_driver(&au8522_driver); --} -- --static __exit void exit_au8522(void) --{ -- i2c_del_driver(&au8522_driver); --} -- --module_init(init_au8522); --module_exit(exit_au8522); -+module_i2c_driver(au8522_driver); -Index: linux-3.3.x86_64/drivers/media/radio/radio-tea5764.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-tea5764.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-tea5764.c -@@ -575,21 +575,7 @@ static struct i2c_driver tea5764_i2c_dri - .id_table = tea5764_id, - }; - --/* init the driver */ --static int __init tea5764_init(void) --{ -- int ret = i2c_add_driver(&tea5764_i2c_driver); -- -- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": " -- DRIVER_DESC "\n"); -- return ret; --} -- --/* cleanup the driver */ --static void __exit tea5764_exit(void) --{ -- i2c_del_driver(&tea5764_i2c_driver); --} -+module_i2c_driver(tea5764_i2c_driver); - - MODULE_AUTHOR(DRIVER_AUTHOR); - MODULE_DESCRIPTION(DRIVER_DESC); -@@ -600,6 +586,3 @@ module_param(use_xtal, int, 0); - MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board"); - module_param(radio_nr, int, 0); - MODULE_PARM_DESC(radio_nr, "video4linux device number to use"); -- --module_init(tea5764_init); --module_exit(tea5764_exit); -Index: linux-3.3.x86_64/drivers/media/radio/saa7706h.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/saa7706h.c -+++ linux-3.3.x86_64/drivers/media/radio/saa7706h.c -@@ -434,18 +434,7 @@ static struct i2c_driver saa7706h_driver - .id_table = saa7706h_id, - }; - --static __init int saa7706h_init(void) --{ -- return i2c_add_driver(&saa7706h_driver); --} -- --static __exit void saa7706h_exit(void) --{ -- i2c_del_driver(&saa7706h_driver); --} -- --module_init(saa7706h_init); --module_exit(saa7706h_exit); -+module_i2c_driver(saa7706h_driver); - - MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver"); - MODULE_AUTHOR("Mocean Laboratories"); -Index: linux-3.3.x86_64/drivers/media/radio/si470x/radio-si470x-i2c.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/si470x/radio-si470x-i2c.c -+++ linux-3.3.x86_64/drivers/media/radio/si470x/radio-si470x-i2c.c -@@ -539,33 +539,7 @@ static struct i2c_driver si470x_i2c_driv - .id_table = si470x_i2c_id, - }; - -- -- --/************************************************************************** -- * Module Interface -- **************************************************************************/ -- --/* -- * si470x_i2c_init - module init -- */ --static int __init si470x_i2c_init(void) --{ -- printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); -- return i2c_add_driver(&si470x_i2c_driver); --} -- -- --/* -- * si470x_i2c_exit - module exit -- */ --static void __exit si470x_i2c_exit(void) --{ -- i2c_del_driver(&si470x_i2c_driver); --} -- -- --module_init(si470x_i2c_init); --module_exit(si470x_i2c_exit); -+module_i2c_driver(si470x_i2c_driver); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR(DRIVER_AUTHOR); -Index: linux-3.3.x86_64/drivers/media/radio/si4713-i2c.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/si4713-i2c.c -+++ linux-3.3.x86_64/drivers/media/radio/si4713-i2c.c -@@ -2106,17 +2106,4 @@ static struct i2c_driver si4713_i2c_driv - .id_table = si4713_id, - }; - --/* Module Interface */ --static int __init si4713_module_init(void) --{ -- return i2c_add_driver(&si4713_i2c_driver); --} -- --static void __exit si4713_module_exit(void) --{ -- i2c_del_driver(&si4713_i2c_driver); --} -- --module_init(si4713_module_init); --module_exit(si4713_module_exit); -- -+module_i2c_driver(si4713_i2c_driver); -Index: linux-3.3.x86_64/drivers/media/radio/tef6862.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/tef6862.c -+++ linux-3.3.x86_64/drivers/media/radio/tef6862.c -@@ -215,20 +215,8 @@ static struct i2c_driver tef6862_driver - .id_table = tef6862_id, - }; - --static __init int tef6862_init(void) --{ -- return i2c_add_driver(&tef6862_driver); --} -- --static __exit void tef6862_exit(void) --{ -- i2c_del_driver(&tef6862_driver); --} -- --module_init(tef6862_init); --module_exit(tef6862_exit); -+module_i2c_driver(tef6862_driver); - - MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner"); - MODULE_AUTHOR("Mocean Laboratories"); - MODULE_LICENSE("GPL v2"); -- -Index: linux-3.3.x86_64/drivers/media/video/adp1653.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/adp1653.c -+++ linux-3.3.x86_64/drivers/media/video/adp1653.c -@@ -33,7 +33,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -482,24 +481,7 @@ static struct i2c_driver adp1653_i2c_dri - .id_table = adp1653_id_table, - }; - --static int __init adp1653_init(void) --{ -- int rval; -- -- rval = i2c_add_driver(&adp1653_i2c_driver); -- if (rval) -- printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__); -- -- return rval; --} -- --static void __exit adp1653_exit(void) --{ -- i2c_del_driver(&adp1653_i2c_driver); --} -- --module_init(adp1653_init); --module_exit(adp1653_exit); -+module_i2c_driver(adp1653_i2c_driver); - - MODULE_AUTHOR("Sakari Ailus "); - MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver"); -Index: linux-3.3.x86_64/drivers/media/video/adv7170.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/adv7170.c -+++ linux-3.3.x86_64/drivers/media/video/adv7170.c -@@ -407,15 +407,4 @@ static struct i2c_driver adv7170_driver - .id_table = adv7170_id, - }; - --static __init int init_adv7170(void) --{ -- return i2c_add_driver(&adv7170_driver); --} -- --static __exit void exit_adv7170(void) --{ -- i2c_del_driver(&adv7170_driver); --} -- --module_init(init_adv7170); --module_exit(exit_adv7170); -+module_i2c_driver(adv7170_driver); -Index: linux-3.3.x86_64/drivers/media/video/adv7175.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/adv7175.c -+++ linux-3.3.x86_64/drivers/media/video/adv7175.c -@@ -457,15 +457,4 @@ static struct i2c_driver adv7175_driver - .id_table = adv7175_id, - }; - --static __init int init_adv7175(void) --{ -- return i2c_add_driver(&adv7175_driver); --} -- --static __exit void exit_adv7175(void) --{ -- i2c_del_driver(&adv7175_driver); --} -- --module_init(init_adv7175); --module_exit(exit_adv7175); -+module_i2c_driver(adv7175_driver); -Index: linux-3.3.x86_64/drivers/media/video/adv7180.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/adv7180.c -+++ linux-3.3.x86_64/drivers/media/video/adv7180.c -@@ -444,20 +444,8 @@ static struct i2c_driver adv7180_driver - .id_table = adv7180_id, - }; - --static __init int adv7180_init(void) --{ -- return i2c_add_driver(&adv7180_driver); --} -- --static __exit void adv7180_exit(void) --{ -- i2c_del_driver(&adv7180_driver); --} -- --module_init(adv7180_init); --module_exit(adv7180_exit); -+module_i2c_driver(adv7180_driver); - - MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); - MODULE_AUTHOR("Mocean Laboratories"); - MODULE_LICENSE("GPL v2"); -- -Index: linux-3.3.x86_64/drivers/media/video/adv7343.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/adv7343.c -+++ linux-3.3.x86_64/drivers/media/video/adv7343.c -@@ -475,15 +475,4 @@ static struct i2c_driver adv7343_driver - .id_table = adv7343_id, - }; - --static __init int init_adv7343(void) --{ -- return i2c_add_driver(&adv7343_driver); --} -- --static __exit void exit_adv7343(void) --{ -- i2c_del_driver(&adv7343_driver); --} -- --module_init(init_adv7343); --module_exit(exit_adv7343); -+module_i2c_driver(adv7343_driver); -Index: linux-3.3.x86_64/drivers/media/video/ak881x.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ak881x.c -+++ linux-3.3.x86_64/drivers/media/video/ak881x.c -@@ -352,18 +352,7 @@ static struct i2c_driver ak881x_i2c_driv - .id_table = ak881x_id, - }; - --static int __init ak881x_module_init(void) --{ -- return i2c_add_driver(&ak881x_i2c_driver); --} -- --static void __exit ak881x_module_exit(void) --{ -- i2c_del_driver(&ak881x_i2c_driver); --} -- --module_init(ak881x_module_init); --module_exit(ak881x_module_exit); -+module_i2c_driver(ak881x_i2c_driver); - - MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814"); - MODULE_AUTHOR("Guennadi Liakhovetski "); -Index: linux-3.3.x86_64/drivers/media/video/as3645a.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/as3645a.c -+++ linux-3.3.x86_64/drivers/media/video/as3645a.c -@@ -881,24 +881,7 @@ static struct i2c_driver as3645a_i2c_dri - .id_table = as3645a_id_table, - }; - --static int __init as3645a_init(void) --{ -- int rval; -- -- rval = i2c_add_driver(&as3645a_i2c_driver); -- if (rval) -- pr_err("%s: Failed to register the driver\n", AS3645A_NAME); -- -- return rval; --} -- --static void __exit as3645a_exit(void) --{ -- i2c_del_driver(&as3645a_i2c_driver); --} -- --module_init(as3645a_init); --module_exit(as3645a_exit); -+module_i2c_driver(as3645a_i2c_driver); - - MODULE_AUTHOR("Laurent Pinchart "); - MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones"); -Index: linux-3.3.x86_64/drivers/media/video/bt819.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/bt819.c -+++ linux-3.3.x86_64/drivers/media/video/bt819.c -@@ -514,15 +514,4 @@ static struct i2c_driver bt819_driver = - .id_table = bt819_id, - }; - --static __init int init_bt819(void) --{ -- return i2c_add_driver(&bt819_driver); --} -- --static __exit void exit_bt819(void) --{ -- i2c_del_driver(&bt819_driver); --} -- --module_init(init_bt819); --module_exit(exit_bt819); -+module_i2c_driver(bt819_driver); -Index: linux-3.3.x86_64/drivers/media/video/bt856.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/bt856.c -+++ linux-3.3.x86_64/drivers/media/video/bt856.c -@@ -270,15 +270,4 @@ static struct i2c_driver bt856_driver = - .id_table = bt856_id, - }; - --static __init int init_bt856(void) --{ -- return i2c_add_driver(&bt856_driver); --} -- --static __exit void exit_bt856(void) --{ -- i2c_del_driver(&bt856_driver); --} -- --module_init(init_bt856); --module_exit(exit_bt856); -+module_i2c_driver(bt856_driver); -Index: linux-3.3.x86_64/drivers/media/video/bt866.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/bt866.c -+++ linux-3.3.x86_64/drivers/media/video/bt866.c -@@ -240,15 +240,4 @@ static struct i2c_driver bt866_driver = - .id_table = bt866_id, - }; - --static __init int init_bt866(void) --{ -- return i2c_add_driver(&bt866_driver); --} -- --static __exit void exit_bt866(void) --{ -- i2c_del_driver(&bt866_driver); --} -- --module_init(init_bt866); --module_exit(exit_bt866); -+module_i2c_driver(bt866_driver); -Index: linux-3.3.x86_64/drivers/media/video/cs5345.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cs5345.c -+++ linux-3.3.x86_64/drivers/media/video/cs5345.c -@@ -249,15 +249,4 @@ static struct i2c_driver cs5345_driver = - .id_table = cs5345_id, - }; - --static __init int init_cs5345(void) --{ -- return i2c_add_driver(&cs5345_driver); --} -- --static __exit void exit_cs5345(void) --{ -- i2c_del_driver(&cs5345_driver); --} -- --module_init(init_cs5345); --module_exit(exit_cs5345); -+module_i2c_driver(cs5345_driver); -Index: linux-3.3.x86_64/drivers/media/video/cs53l32a.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cs53l32a.c -+++ linux-3.3.x86_64/drivers/media/video/cs53l32a.c -@@ -248,15 +248,4 @@ static struct i2c_driver cs53l32a_driver - .id_table = cs53l32a_id, - }; - --static __init int init_cs53l32a(void) --{ -- return i2c_add_driver(&cs53l32a_driver); --} -- --static __exit void exit_cs53l32a(void) --{ -- i2c_del_driver(&cs53l32a_driver); --} -- --module_init(init_cs53l32a); --module_exit(exit_cs53l32a); -+module_i2c_driver(cs53l32a_driver); -Index: linux-3.3.x86_64/drivers/media/video/cx25840/cx25840-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx25840/cx25840-core.c -+++ linux-3.3.x86_64/drivers/media/video/cx25840/cx25840-core.c -@@ -5301,15 +5301,4 @@ static struct i2c_driver cx25840_driver - .id_table = cx25840_id, - }; - --static __init int init_cx25840(void) --{ -- return i2c_add_driver(&cx25840_driver); --} -- --static __exit void exit_cx25840(void) --{ -- i2c_del_driver(&cx25840_driver); --} -- --module_init(init_cx25840); --module_exit(exit_cx25840); -+module_i2c_driver(cx25840_driver); -Index: linux-3.3.x86_64/drivers/media/video/imx074.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/imx074.c -+++ linux-3.3.x86_64/drivers/media/video/imx074.c -@@ -468,18 +468,7 @@ static struct i2c_driver imx074_i2c_driv - .id_table = imx074_id, - }; - --static int __init imx074_mod_init(void) --{ -- return i2c_add_driver(&imx074_i2c_driver); --} -- --static void __exit imx074_mod_exit(void) --{ -- i2c_del_driver(&imx074_i2c_driver); --} -- --module_init(imx074_mod_init); --module_exit(imx074_mod_exit); -+module_i2c_driver(imx074_i2c_driver); - - MODULE_DESCRIPTION("Sony IMX074 Camera driver"); - MODULE_AUTHOR("Guennadi Liakhovetski "); -Index: linux-3.3.x86_64/drivers/media/video/indycam.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/indycam.c -+++ linux-3.3.x86_64/drivers/media/video/indycam.c -@@ -387,15 +387,4 @@ static struct i2c_driver indycam_driver - .id_table = indycam_id, - }; - --static __init int init_indycam(void) --{ -- return i2c_add_driver(&indycam_driver); --} -- --static __exit void exit_indycam(void) --{ -- i2c_del_driver(&indycam_driver); --} -- --module_init(init_indycam); --module_exit(exit_indycam); -+module_i2c_driver(indycam_driver); -Index: linux-3.3.x86_64/drivers/media/video/ir-kbd-i2c.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ir-kbd-i2c.c -+++ linux-3.3.x86_64/drivers/media/video/ir-kbd-i2c.c -@@ -471,7 +471,7 @@ static const struct i2c_device_id ir_kbd - { } - }; - --static struct i2c_driver driver = { -+static struct i2c_driver ir_kbd_driver = { - .driver = { - .name = "ir-kbd-i2c", - }, -@@ -480,21 +480,10 @@ static struct i2c_driver driver = { - .id_table = ir_kbd_id, - }; - -+module_i2c_driver(ir_kbd_driver); -+ - /* ----------------------------------------------------------------------- */ - - MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller"); - MODULE_DESCRIPTION("input driver for i2c IR remote controls"); - MODULE_LICENSE("GPL"); -- --static int __init ir_init(void) --{ -- return i2c_add_driver(&driver); --} -- --static void __exit ir_fini(void) --{ -- i2c_del_driver(&driver); --} -- --module_init(ir_init); --module_exit(ir_fini); -Index: linux-3.3.x86_64/drivers/media/video/ks0127.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ks0127.c -+++ linux-3.3.x86_64/drivers/media/video/ks0127.c -@@ -721,15 +721,4 @@ static struct i2c_driver ks0127_driver = - .id_table = ks0127_id, - }; - --static __init int init_ks0127(void) --{ -- return i2c_add_driver(&ks0127_driver); --} -- --static __exit void exit_ks0127(void) --{ -- i2c_del_driver(&ks0127_driver); --} -- --module_init(init_ks0127); --module_exit(exit_ks0127); -+module_i2c_driver(ks0127_driver); -Index: linux-3.3.x86_64/drivers/media/video/m52790.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/m52790.c -+++ linux-3.3.x86_64/drivers/media/video/m52790.c -@@ -213,15 +213,4 @@ static struct i2c_driver m52790_driver = - .id_table = m52790_id, - }; - --static __init int init_m52790(void) --{ -- return i2c_add_driver(&m52790_driver); --} -- --static __exit void exit_m52790(void) --{ -- i2c_del_driver(&m52790_driver); --} -- --module_init(init_m52790); --module_exit(exit_m52790); -+module_i2c_driver(m52790_driver); -Index: linux-3.3.x86_64/drivers/media/video/msp3400-driver.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/msp3400-driver.c -+++ linux-3.3.x86_64/drivers/media/video/msp3400-driver.c -@@ -881,18 +881,7 @@ static struct i2c_driver msp_driver = { - .id_table = msp_id, - }; - --static __init int init_msp(void) --{ -- return i2c_add_driver(&msp_driver); --} -- --static __exit void exit_msp(void) --{ -- i2c_del_driver(&msp_driver); --} -- --module_init(init_msp); --module_exit(exit_msp); -+module_i2c_driver(msp_driver); - - /* - * Overrides for Emacs so that we follow Linus's tabbing style. -Index: linux-3.3.x86_64/drivers/media/video/mt9m001.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9m001.c -+++ linux-3.3.x86_64/drivers/media/video/mt9m001.c -@@ -730,18 +730,7 @@ static struct i2c_driver mt9m001_i2c_dri - .id_table = mt9m001_id, - }; - --static int __init mt9m001_mod_init(void) --{ -- return i2c_add_driver(&mt9m001_i2c_driver); --} -- --static void __exit mt9m001_mod_exit(void) --{ -- i2c_del_driver(&mt9m001_i2c_driver); --} -- --module_init(mt9m001_mod_init); --module_exit(mt9m001_mod_exit); -+module_i2c_driver(mt9m001_i2c_driver); - - MODULE_DESCRIPTION("Micron MT9M001 Camera driver"); - MODULE_AUTHOR("Guennadi Liakhovetski "); -Index: linux-3.3.x86_64/drivers/media/video/mt9m111.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9m111.c -+++ linux-3.3.x86_64/drivers/media/video/mt9m111.c -@@ -1008,18 +1008,7 @@ static struct i2c_driver mt9m111_i2c_dri - .id_table = mt9m111_id, - }; - --static int __init mt9m111_mod_init(void) --{ -- return i2c_add_driver(&mt9m111_i2c_driver); --} -- --static void __exit mt9m111_mod_exit(void) --{ -- i2c_del_driver(&mt9m111_i2c_driver); --} -- --module_init(mt9m111_mod_init); --module_exit(mt9m111_mod_exit); -+module_i2c_driver(mt9m111_i2c_driver); - - MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver"); - MODULE_AUTHOR("Robert Jarzmik"); -Index: linux-3.3.x86_64/drivers/media/video/mt9p031.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9p031.c -+++ linux-3.3.x86_64/drivers/media/video/mt9p031.c -@@ -19,7 +19,6 @@ - #include - #include - #include --#include - #include - - #include -@@ -28,6 +27,8 @@ - #include - #include - -+#include "aptina-pll.h" -+ - #define MT9P031_PIXEL_ARRAY_WIDTH 2752 - #define MT9P031_PIXEL_ARRAY_HEIGHT 2004 - -@@ -98,14 +99,6 @@ - #define MT9P031_TEST_PATTERN_RED 0xa2 - #define MT9P031_TEST_PATTERN_BLUE 0xa3 - --struct mt9p031_pll_divs { -- u32 ext_freq; -- u32 target_freq; -- u8 m; -- u8 n; -- u8 p1; --}; -- - struct mt9p031 { - struct v4l2_subdev subdev; - struct media_pad pad; -@@ -115,10 +108,8 @@ struct mt9p031 { - struct mt9p031_platform_data *pdata; - struct mutex power_lock; /* lock to protect power_count */ - int power_count; -- u16 xskip; -- u16 yskip; - -- const struct mt9p031_pll_divs *pll; -+ struct aptina_pll pll; - - /* Registers cache */ - u16 output_control; -@@ -186,33 +177,31 @@ static int mt9p031_reset(struct mt9p031 - 0); - } - --/* -- * This static table uses ext_freq and vdd_io values to select suitable -- * PLL dividers m, n and p1 which have been calculated as specifiec in p36 -- * of Aptina's mt9p031 datasheet. New values should be added here. -- */ --static const struct mt9p031_pll_divs mt9p031_divs[] = { -- /* ext_freq target_freq m n p1 */ -- {21000000, 48000000, 26, 2, 6} --}; -- --static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031) -+static int mt9p031_pll_setup(struct mt9p031 *mt9p031) - { -+ static const struct aptina_pll_limits limits = { -+ .ext_clock_min = 6000000, -+ .ext_clock_max = 27000000, -+ .int_clock_min = 2000000, -+ .int_clock_max = 13500000, -+ .out_clock_min = 180000000, -+ .out_clock_max = 360000000, -+ .pix_clock_max = 96000000, -+ .n_min = 1, -+ .n_max = 64, -+ .m_min = 16, -+ .m_max = 255, -+ .p1_min = 1, -+ .p1_max = 128, -+ }; -+ - struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); -- int i; -+ struct mt9p031_platform_data *pdata = mt9p031->pdata; - -- for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) { -- if (mt9p031_divs[i].ext_freq == mt9p031->pdata->ext_freq && -- mt9p031_divs[i].target_freq == mt9p031->pdata->target_freq) { -- mt9p031->pll = &mt9p031_divs[i]; -- return 0; -- } -- } -+ mt9p031->pll.ext_clock = pdata->ext_freq; -+ mt9p031->pll.pix_clock = pdata->target_freq; - -- dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %d, " -- "target_freq = %d\n", mt9p031->pdata->ext_freq, -- mt9p031->pdata->target_freq); -- return -EINVAL; -+ return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll); - } - - static int mt9p031_pll_enable(struct mt9p031 *mt9p031) -@@ -226,11 +215,11 @@ static int mt9p031_pll_enable(struct mt9 - return ret; - - ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1, -- (mt9p031->pll->m << 8) | (mt9p031->pll->n - 1)); -+ (mt9p031->pll.m << 8) | (mt9p031->pll.n - 1)); - if (ret < 0) - return ret; - -- ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll->p1 - 1); -+ ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1); - if (ret < 0) - return ret; - -@@ -785,8 +774,6 @@ static int mt9p031_open(struct v4l2_subd - format->field = V4L2_FIELD_NONE; - format->colorspace = V4L2_COLORSPACE_SRGB; - -- mt9p031->xskip = 1; -- mt9p031->yskip = 1; - return mt9p031_set_power(subdev, 1); - } - -@@ -905,7 +892,7 @@ static int mt9p031_probe(struct i2c_clie - mt9p031->format.field = V4L2_FIELD_NONE; - mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; - -- ret = mt9p031_pll_get_divs(mt9p031); -+ ret = mt9p031_pll_setup(mt9p031); - - done: - if (ret < 0) { -@@ -945,18 +932,7 @@ static struct i2c_driver mt9p031_i2c_dri - .id_table = mt9p031_id, - }; - --static int __init mt9p031_mod_init(void) --{ -- return i2c_add_driver(&mt9p031_i2c_driver); --} -- --static void __exit mt9p031_mod_exit(void) --{ -- i2c_del_driver(&mt9p031_i2c_driver); --} -- --module_init(mt9p031_mod_init); --module_exit(mt9p031_mod_exit); -+module_i2c_driver(mt9p031_i2c_driver); - - MODULE_DESCRIPTION("Aptina MT9P031 Camera driver"); - MODULE_AUTHOR("Bastian Hecht "); -Index: linux-3.3.x86_64/drivers/media/video/mt9t001.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9t001.c -+++ linux-3.3.x86_64/drivers/media/video/mt9t001.c -@@ -817,18 +817,7 @@ static struct i2c_driver mt9t001_driver - .id_table = mt9t001_id, - }; - --static int __init mt9t001_init(void) --{ -- return i2c_add_driver(&mt9t001_driver); --} -- --static void __exit mt9t001_exit(void) --{ -- i2c_del_driver(&mt9t001_driver); --} -- --module_init(mt9t001_init); --module_exit(mt9t001_exit); -+module_i2c_driver(mt9t001_driver); - - MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver"); - MODULE_AUTHOR("Laurent Pinchart "); -Index: linux-3.3.x86_64/drivers/media/video/mt9t031.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9t031.c -+++ linux-3.3.x86_64/drivers/media/video/mt9t031.c -@@ -850,18 +850,7 @@ static struct i2c_driver mt9t031_i2c_dri - .id_table = mt9t031_id, - }; - --static int __init mt9t031_mod_init(void) --{ -- return i2c_add_driver(&mt9t031_i2c_driver); --} -- --static void __exit mt9t031_mod_exit(void) --{ -- i2c_del_driver(&mt9t031_i2c_driver); --} -- --module_init(mt9t031_mod_init); --module_exit(mt9t031_mod_exit); -+module_i2c_driver(mt9t031_i2c_driver); - - MODULE_DESCRIPTION("Micron MT9T031 Camera driver"); - MODULE_AUTHOR("Guennadi Liakhovetski "); -Index: linux-3.3.x86_64/drivers/media/video/mt9t112.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9t112.c -+++ linux-3.3.x86_64/drivers/media/video/mt9t112.c -@@ -1117,21 +1117,7 @@ static struct i2c_driver mt9t112_i2c_dri - .id_table = mt9t112_id, - }; - --/************************************************************************ -- module function --************************************************************************/ --static int __init mt9t112_module_init(void) --{ -- return i2c_add_driver(&mt9t112_i2c_driver); --} -- --static void __exit mt9t112_module_exit(void) --{ -- i2c_del_driver(&mt9t112_i2c_driver); --} -- --module_init(mt9t112_module_init); --module_exit(mt9t112_module_exit); -+module_i2c_driver(mt9t112_i2c_driver); - - MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); - MODULE_AUTHOR("Kuninori Morimoto"); -Index: linux-3.3.x86_64/drivers/media/video/mt9v011.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9v011.c -+++ linux-3.3.x86_64/drivers/media/video/mt9v011.c -@@ -709,15 +709,4 @@ static struct i2c_driver mt9v011_driver - .id_table = mt9v011_id, - }; - --static __init int init_mt9v011(void) --{ -- return i2c_add_driver(&mt9v011_driver); --} -- --static __exit void exit_mt9v011(void) --{ -- i2c_del_driver(&mt9v011_driver); --} -- --module_init(init_mt9v011); --module_exit(exit_mt9v011); -+module_i2c_driver(mt9v011_driver); -Index: linux-3.3.x86_64/drivers/media/video/mt9v022.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9v022.c -+++ linux-3.3.x86_64/drivers/media/video/mt9v022.c -@@ -872,18 +872,7 @@ static struct i2c_driver mt9v022_i2c_dri - .id_table = mt9v022_id, - }; - --static int __init mt9v022_mod_init(void) --{ -- return i2c_add_driver(&mt9v022_i2c_driver); --} -- --static void __exit mt9v022_mod_exit(void) --{ -- i2c_del_driver(&mt9v022_i2c_driver); --} -- --module_init(mt9v022_mod_init); --module_exit(mt9v022_mod_exit); -+module_i2c_driver(mt9v022_i2c_driver); - - MODULE_DESCRIPTION("Micron MT9V022 Camera driver"); - MODULE_AUTHOR("Guennadi Liakhovetski "); -Index: linux-3.3.x86_64/drivers/media/video/mt9v032.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mt9v032.c -+++ linux-3.3.x86_64/drivers/media/video/mt9v032.c -@@ -756,18 +756,7 @@ static struct i2c_driver mt9v032_driver - .id_table = mt9v032_id, - }; - --static int __init mt9v032_init(void) --{ -- return i2c_add_driver(&mt9v032_driver); --} -- --static void __exit mt9v032_exit(void) --{ -- i2c_del_driver(&mt9v032_driver); --} -- --module_init(mt9v032_init); --module_exit(mt9v032_exit); -+module_i2c_driver(mt9v032_driver); - - MODULE_DESCRIPTION("Aptina MT9V032 Camera driver"); - MODULE_AUTHOR("Laurent Pinchart "); -Index: linux-3.3.x86_64/drivers/media/video/ov2640.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ov2640.c -+++ linux-3.3.x86_64/drivers/media/video/ov2640.c -@@ -1103,21 +1103,7 @@ static struct i2c_driver ov2640_i2c_driv - .id_table = ov2640_id, - }; - --/* -- * Module functions -- */ --static int __init ov2640_module_init(void) --{ -- return i2c_add_driver(&ov2640_i2c_driver); --} -- --static void __exit ov2640_module_exit(void) --{ -- i2c_del_driver(&ov2640_i2c_driver); --} -- --module_init(ov2640_module_init); --module_exit(ov2640_module_exit); -+module_i2c_driver(ov2640_i2c_driver); - - MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor"); - MODULE_AUTHOR("Alberto Panizzo"); -Index: linux-3.3.x86_64/drivers/media/video/ov5642.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ov5642.c -+++ linux-3.3.x86_64/drivers/media/video/ov5642.c -@@ -1068,18 +1068,7 @@ static struct i2c_driver ov5642_i2c_driv - .id_table = ov5642_id, - }; - --static int __init ov5642_mod_init(void) --{ -- return i2c_add_driver(&ov5642_i2c_driver); --} -- --static void __exit ov5642_mod_exit(void) --{ -- i2c_del_driver(&ov5642_i2c_driver); --} -- --module_init(ov5642_mod_init); --module_exit(ov5642_mod_exit); -+module_i2c_driver(ov5642_i2c_driver); - - MODULE_DESCRIPTION("Omnivision OV5642 Camera driver"); - MODULE_AUTHOR("Bastian Hecht "); -Index: linux-3.3.x86_64/drivers/media/video/ov7670.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ov7670.c -+++ linux-3.3.x86_64/drivers/media/video/ov7670.c -@@ -1583,15 +1583,4 @@ static struct i2c_driver ov7670_driver = - .id_table = ov7670_id, - }; - --static __init int init_ov7670(void) --{ -- return i2c_add_driver(&ov7670_driver); --} -- --static __exit void exit_ov7670(void) --{ -- i2c_del_driver(&ov7670_driver); --} -- --module_init(init_ov7670); --module_exit(exit_ov7670); -+module_i2c_driver(ov7670_driver); -Index: linux-3.3.x86_64/drivers/media/video/ov772x.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ov772x.c -+++ linux-3.3.x86_64/drivers/media/video/ov772x.c -@@ -1123,22 +1123,7 @@ static struct i2c_driver ov772x_i2c_driv - .id_table = ov772x_id, - }; - --/* -- * module function -- */ -- --static int __init ov772x_module_init(void) --{ -- return i2c_add_driver(&ov772x_i2c_driver); --} -- --static void __exit ov772x_module_exit(void) --{ -- i2c_del_driver(&ov772x_i2c_driver); --} -- --module_init(ov772x_module_init); --module_exit(ov772x_module_exit); -+module_i2c_driver(ov772x_i2c_driver); - - MODULE_DESCRIPTION("SoC Camera driver for ov772x"); - MODULE_AUTHOR("Kuninori Morimoto"); -Index: linux-3.3.x86_64/drivers/media/video/ov9640.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ov9640.c -+++ linux-3.3.x86_64/drivers/media/video/ov9640.c -@@ -738,18 +738,7 @@ static struct i2c_driver ov9640_i2c_driv - .id_table = ov9640_id, - }; - --static int __init ov9640_module_init(void) --{ -- return i2c_add_driver(&ov9640_i2c_driver); --} -- --static void __exit ov9640_module_exit(void) --{ -- i2c_del_driver(&ov9640_i2c_driver); --} -- --module_init(ov9640_module_init); --module_exit(ov9640_module_exit); -+module_i2c_driver(ov9640_i2c_driver); - - MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); - MODULE_AUTHOR("Marek Vasut "); -Index: linux-3.3.x86_64/drivers/media/video/ov9740.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ov9740.c -+++ linux-3.3.x86_64/drivers/media/video/ov9740.c -@@ -998,18 +998,7 @@ static struct i2c_driver ov9740_i2c_driv - .id_table = ov9740_id, - }; - --static int __init ov9740_module_init(void) --{ -- return i2c_add_driver(&ov9740_i2c_driver); --} -- --static void __exit ov9740_module_exit(void) --{ -- i2c_del_driver(&ov9740_i2c_driver); --} -- --module_init(ov9740_module_init); --module_exit(ov9740_module_exit); -+module_i2c_driver(ov9740_i2c_driver); - - MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740"); - MODULE_AUTHOR("Andrew Chew "); -Index: linux-3.3.x86_64/drivers/media/video/rj54n1cb0c.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/rj54n1cb0c.c -+++ linux-3.3.x86_64/drivers/media/video/rj54n1cb0c.c -@@ -1407,18 +1407,7 @@ static struct i2c_driver rj54n1_i2c_driv - .id_table = rj54n1_id, - }; - --static int __init rj54n1_mod_init(void) --{ -- return i2c_add_driver(&rj54n1_i2c_driver); --} -- --static void __exit rj54n1_mod_exit(void) --{ -- i2c_del_driver(&rj54n1_i2c_driver); --} -- --module_init(rj54n1_mod_init); --module_exit(rj54n1_mod_exit); -+module_i2c_driver(rj54n1_i2c_driver); - - MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver"); - MODULE_AUTHOR("Guennadi Liakhovetski "); -Index: linux-3.3.x86_64/drivers/media/video/s5p-tv/hdmiphy_drv.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s5p-tv/hdmiphy_drv.c -+++ linux-3.3.x86_64/drivers/media/video/s5p-tv/hdmiphy_drv.c -@@ -175,14 +175,4 @@ static struct i2c_driver hdmiphy_driver - .id_table = hdmiphy_id, - }; - --static int __init hdmiphy_init(void) --{ -- return i2c_add_driver(&hdmiphy_driver); --} --module_init(hdmiphy_init); -- --static void __exit hdmiphy_exit(void) --{ -- i2c_del_driver(&hdmiphy_driver); --} --module_exit(hdmiphy_exit); -+module_i2c_driver(hdmiphy_driver); -Index: linux-3.3.x86_64/drivers/media/video/saa6588.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa6588.c -+++ linux-3.3.x86_64/drivers/media/video/saa6588.c -@@ -539,15 +539,4 @@ static struct i2c_driver saa6588_driver - .id_table = saa6588_id, - }; - --static __init int init_saa6588(void) --{ -- return i2c_add_driver(&saa6588_driver); --} -- --static __exit void exit_saa6588(void) --{ -- i2c_del_driver(&saa6588_driver); --} -- --module_init(init_saa6588); --module_exit(exit_saa6588); -+module_i2c_driver(saa6588_driver); -Index: linux-3.3.x86_64/drivers/media/video/saa7110.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7110.c -+++ linux-3.3.x86_64/drivers/media/video/saa7110.c -@@ -491,15 +491,4 @@ static struct i2c_driver saa7110_driver - .id_table = saa7110_id, - }; - --static __init int init_saa7110(void) --{ -- return i2c_add_driver(&saa7110_driver); --} -- --static __exit void exit_saa7110(void) --{ -- i2c_del_driver(&saa7110_driver); --} -- --module_init(init_saa7110); --module_exit(exit_saa7110); -+module_i2c_driver(saa7110_driver); -Index: linux-3.3.x86_64/drivers/media/video/saa7115.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7115.c -+++ linux-3.3.x86_64/drivers/media/video/saa7115.c -@@ -1724,15 +1724,4 @@ static struct i2c_driver saa711x_driver - .id_table = saa711x_id, - }; - --static __init int init_saa711x(void) --{ -- return i2c_add_driver(&saa711x_driver); --} -- --static __exit void exit_saa711x(void) --{ -- i2c_del_driver(&saa711x_driver); --} -- --module_init(init_saa711x); --module_exit(exit_saa711x); -+module_i2c_driver(saa711x_driver); -Index: linux-3.3.x86_64/drivers/media/video/saa7127.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7127.c -+++ linux-3.3.x86_64/drivers/media/video/saa7127.c -@@ -852,15 +852,4 @@ static struct i2c_driver saa7127_driver - .id_table = saa7127_id, - }; - --static __init int init_saa7127(void) --{ -- return i2c_add_driver(&saa7127_driver); --} -- --static __exit void exit_saa7127(void) --{ -- i2c_del_driver(&saa7127_driver); --} -- --module_init(init_saa7127); --module_exit(exit_saa7127); -+module_i2c_driver(saa7127_driver); -Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa6752hs.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa6752hs.c -+++ linux-3.3.x86_64/drivers/media/video/saa7134/saa6752hs.c -@@ -1001,18 +1001,7 @@ static struct i2c_driver saa6752hs_drive - .id_table = saa6752hs_id, - }; - --static __init int init_saa6752hs(void) --{ -- return i2c_add_driver(&saa6752hs_driver); --} -- --static __exit void exit_saa6752hs(void) --{ -- i2c_del_driver(&saa6752hs_driver); --} -- --module_init(init_saa6752hs); --module_exit(exit_saa6752hs); -+module_i2c_driver(saa6752hs_driver); - - /* - * Overrides for Emacs so that we follow Linus's tabbing style. -Index: linux-3.3.x86_64/drivers/media/video/saa717x.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa717x.c -+++ linux-3.3.x86_64/drivers/media/video/saa717x.c -@@ -1375,15 +1375,4 @@ static struct i2c_driver saa717x_driver - .id_table = saa717x_id, - }; - --static __init int init_saa717x(void) --{ -- return i2c_add_driver(&saa717x_driver); --} -- --static __exit void exit_saa717x(void) --{ -- i2c_del_driver(&saa717x_driver); --} -- --module_init(init_saa717x); --module_exit(exit_saa717x); -+module_i2c_driver(saa717x_driver); -Index: linux-3.3.x86_64/drivers/media/video/saa7185.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7185.c -+++ linux-3.3.x86_64/drivers/media/video/saa7185.c -@@ -374,15 +374,4 @@ static struct i2c_driver saa7185_driver - .id_table = saa7185_id, - }; - --static __init int init_saa7185(void) --{ -- return i2c_add_driver(&saa7185_driver); --} -- --static __exit void exit_saa7185(void) --{ -- i2c_del_driver(&saa7185_driver); --} -- --module_init(init_saa7185); --module_exit(exit_saa7185); -+module_i2c_driver(saa7185_driver); -Index: linux-3.3.x86_64/drivers/media/video/saa7191.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7191.c -+++ linux-3.3.x86_64/drivers/media/video/saa7191.c -@@ -656,15 +656,4 @@ static struct i2c_driver saa7191_driver - .id_table = saa7191_id, - }; - --static __init int init_saa7191(void) --{ -- return i2c_add_driver(&saa7191_driver); --} -- --static __exit void exit_saa7191(void) --{ -- i2c_del_driver(&saa7191_driver); --} -- --module_init(init_saa7191); --module_exit(exit_saa7191); -+module_i2c_driver(saa7191_driver); -Index: linux-3.3.x86_64/drivers/media/video/sr030pc30.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/sr030pc30.c -+++ linux-3.3.x86_64/drivers/media/video/sr030pc30.c -@@ -864,18 +864,7 @@ static struct i2c_driver sr030pc30_i2c_d - .id_table = sr030pc30_id, - }; - --static int __init sr030pc30_init(void) --{ -- return i2c_add_driver(&sr030pc30_i2c_driver); --} -- --static void __exit sr030pc30_exit(void) --{ -- i2c_del_driver(&sr030pc30_i2c_driver); --} -- --module_init(sr030pc30_init); --module_exit(sr030pc30_exit); -+module_i2c_driver(sr030pc30_i2c_driver); - - MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver"); - MODULE_AUTHOR("Sylwester Nawrocki "); -Index: linux-3.3.x86_64/drivers/media/video/tda7432.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tda7432.c -+++ linux-3.3.x86_64/drivers/media/video/tda7432.c -@@ -482,15 +482,4 @@ static struct i2c_driver tda7432_driver - .id_table = tda7432_id, - }; - --static __init int init_tda7432(void) --{ -- return i2c_add_driver(&tda7432_driver); --} -- --static __exit void exit_tda7432(void) --{ -- i2c_del_driver(&tda7432_driver); --} -- --module_init(init_tda7432); --module_exit(exit_tda7432); -+module_i2c_driver(tda7432_driver); -Index: linux-3.3.x86_64/drivers/media/video/tda9840.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tda9840.c -+++ linux-3.3.x86_64/drivers/media/video/tda9840.c -@@ -208,15 +208,4 @@ static struct i2c_driver tda9840_driver - .id_table = tda9840_id, - }; - --static __init int init_tda9840(void) --{ -- return i2c_add_driver(&tda9840_driver); --} -- --static __exit void exit_tda9840(void) --{ -- i2c_del_driver(&tda9840_driver); --} -- --module_init(init_tda9840); --module_exit(exit_tda9840); -+module_i2c_driver(tda9840_driver); -Index: linux-3.3.x86_64/drivers/media/video/tea6415c.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tea6415c.c -+++ linux-3.3.x86_64/drivers/media/video/tea6415c.c -@@ -184,15 +184,4 @@ static struct i2c_driver tea6415c_driver - .id_table = tea6415c_id, - }; - --static __init int init_tea6415c(void) --{ -- return i2c_add_driver(&tea6415c_driver); --} -- --static __exit void exit_tea6415c(void) --{ -- i2c_del_driver(&tea6415c_driver); --} -- --module_init(init_tea6415c); --module_exit(exit_tea6415c); -+module_i2c_driver(tea6415c_driver); -Index: linux-3.3.x86_64/drivers/media/video/tea6420.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tea6420.c -+++ linux-3.3.x86_64/drivers/media/video/tea6420.c -@@ -166,15 +166,4 @@ static struct i2c_driver tea6420_driver - .id_table = tea6420_id, - }; - --static __init int init_tea6420(void) --{ -- return i2c_add_driver(&tea6420_driver); --} -- --static __exit void exit_tea6420(void) --{ -- i2c_del_driver(&tea6420_driver); --} -- --module_init(init_tea6420); --module_exit(exit_tea6420); -+module_i2c_driver(tea6420_driver); -Index: linux-3.3.x86_64/drivers/media/video/ths7303.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ths7303.c -+++ linux-3.3.x86_64/drivers/media/video/ths7303.c -@@ -137,16 +137,4 @@ static struct i2c_driver ths7303_driver - .id_table = ths7303_id, - }; - --static int __init ths7303_init(void) --{ -- return i2c_add_driver(&ths7303_driver); --} -- --static void __exit ths7303_exit(void) --{ -- i2c_del_driver(&ths7303_driver); --} -- --module_init(ths7303_init); --module_exit(ths7303_exit); -- -+module_i2c_driver(ths7303_driver); -Index: linux-3.3.x86_64/drivers/media/video/tlv320aic23b.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tlv320aic23b.c -+++ linux-3.3.x86_64/drivers/media/video/tlv320aic23b.c -@@ -227,15 +227,4 @@ static struct i2c_driver tlv320aic23b_dr - .id_table = tlv320aic23b_id, - }; - --static __init int init_tlv320aic23b(void) --{ -- return i2c_add_driver(&tlv320aic23b_driver); --} -- --static __exit void exit_tlv320aic23b(void) --{ -- i2c_del_driver(&tlv320aic23b_driver); --} -- --module_init(init_tlv320aic23b); --module_exit(exit_tlv320aic23b); -+module_i2c_driver(tlv320aic23b_driver); -Index: linux-3.3.x86_64/drivers/media/video/tvaudio.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tvaudio.c -+++ linux-3.3.x86_64/drivers/media/video/tvaudio.c -@@ -2078,15 +2078,4 @@ static struct i2c_driver tvaudio_driver - .id_table = tvaudio_id, - }; - --static __init int init_tvaudio(void) --{ -- return i2c_add_driver(&tvaudio_driver); --} -- --static __exit void exit_tvaudio(void) --{ -- i2c_del_driver(&tvaudio_driver); --} -- --module_init(init_tvaudio); --module_exit(exit_tvaudio); -+module_i2c_driver(tvaudio_driver); -Index: linux-3.3.x86_64/drivers/media/video/tvp514x.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tvp514x.c -+++ linux-3.3.x86_64/drivers/media/video/tvp514x.c -@@ -1163,15 +1163,4 @@ static struct i2c_driver tvp514x_driver - .id_table = tvp514x_id, - }; - --static int __init tvp514x_init(void) --{ -- return i2c_add_driver(&tvp514x_driver); --} -- --static void __exit tvp514x_exit(void) --{ -- i2c_del_driver(&tvp514x_driver); --} -- --module_init(tvp514x_init); --module_exit(tvp514x_exit); -+module_i2c_driver(tvp514x_driver); -Index: linux-3.3.x86_64/drivers/media/video/tvp5150.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tvp5150.c -+++ linux-3.3.x86_64/drivers/media/video/tvp5150.c -@@ -17,6 +17,13 @@ - - #include "tvp5150_reg.h" - -+#define TVP5150_H_MAX 720 -+#define TVP5150_V_MAX_525_60 480 -+#define TVP5150_V_MAX_OTHERS 576 -+#define TVP5150_MAX_CROP_LEFT 511 -+#define TVP5150_MAX_CROP_TOP 127 -+#define TVP5150_CROP_SHIFT 2 -+ - MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); - MODULE_AUTHOR("Mauro Carvalho Chehab"); - MODULE_LICENSE("GPL"); -@@ -29,6 +36,7 @@ MODULE_PARM_DESC(debug, "Debug level (0- - struct tvp5150 { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; -+ struct v4l2_rect rect; - - v4l2_std_id norm; /* Current set standard */ - u32 input; -@@ -732,6 +740,13 @@ static int tvp5150_s_std(struct v4l2_sub - if (decoder->norm == std) - return 0; - -+ /* Change cropping height limits */ -+ if (std & V4L2_STD_525_60) -+ decoder->rect.height = TVP5150_V_MAX_525_60; -+ else -+ decoder->rect.height = TVP5150_V_MAX_OTHERS; -+ -+ - return tvp5150_set_std(sd, std); - } - -@@ -828,11 +843,8 @@ static int tvp5150_mbus_fmt(struct v4l2_ - else - std = decoder->norm; - -- f->width = 720; -- if (std & V4L2_STD_525_60) -- f->height = 480; -- else -- f->height = 576; -+ f->width = decoder->rect.width; -+ f->height = decoder->rect.height; - - f->code = V4L2_MBUS_FMT_YUYV8_2X8; - f->field = V4L2_FIELD_SEQ_TB; -@@ -843,6 +855,99 @@ static int tvp5150_mbus_fmt(struct v4l2_ - return 0; - } - -+static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -+{ -+ struct v4l2_rect rect = a->c; -+ struct tvp5150 *decoder = to_tvp5150(sd); -+ v4l2_std_id std; -+ int hmax; -+ -+ v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", -+ __func__, rect.left, rect.top, rect.width, rect.height); -+ -+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ -+ /* tvp5150 has some special limits */ -+ rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); -+ rect.width = clamp(rect.width, -+ TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, -+ TVP5150_H_MAX - rect.left); -+ rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); -+ -+ /* Calculate height based on current standard */ -+ if (decoder->norm == V4L2_STD_ALL) -+ std = tvp5150_read_std(sd); -+ else -+ std = decoder->norm; -+ -+ if (std & V4L2_STD_525_60) -+ hmax = TVP5150_V_MAX_525_60; -+ else -+ hmax = TVP5150_V_MAX_OTHERS; -+ -+ rect.height = clamp(rect.height, -+ hmax - TVP5150_MAX_CROP_TOP - rect.top, -+ hmax - rect.top); -+ -+ tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top); -+ tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, -+ rect.top + rect.height - hmax); -+ tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB, -+ rect.left >> TVP5150_CROP_SHIFT); -+ tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB, -+ rect.left | (1 << TVP5150_CROP_SHIFT)); -+ tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB, -+ (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> -+ TVP5150_CROP_SHIFT); -+ tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB, -+ rect.left + rect.width - TVP5150_MAX_CROP_LEFT); -+ -+ decoder->rect = rect; -+ -+ return 0; -+} -+ -+static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -+{ -+ struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); -+ -+ a->c = decoder->rect; -+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ -+ return 0; -+} -+ -+static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -+{ -+ struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); -+ v4l2_std_id std; -+ -+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ -+ a->bounds.left = 0; -+ a->bounds.top = 0; -+ a->bounds.width = TVP5150_H_MAX; -+ -+ /* Calculate height based on current standard */ -+ if (decoder->norm == V4L2_STD_ALL) -+ std = tvp5150_read_std(sd); -+ else -+ std = decoder->norm; -+ -+ if (std & V4L2_STD_525_60) -+ a->bounds.height = TVP5150_V_MAX_525_60; -+ else -+ a->bounds.height = TVP5150_V_MAX_OTHERS; -+ -+ a->defrect = a->bounds; -+ a->pixelaspect.numerator = 1; -+ a->pixelaspect.denominator = 1; -+ -+ return 0; -+} -+ - /**************************************************************************** - I2C Command - ****************************************************************************/ -@@ -998,6 +1103,10 @@ static const struct v4l2_subdev_video_op - .enum_mbus_fmt = tvp5150_enum_mbus_fmt, - .s_mbus_fmt = tvp5150_mbus_fmt, - .try_mbus_fmt = tvp5150_mbus_fmt, -+ .g_mbus_fmt = tvp5150_mbus_fmt, -+ .s_crop = tvp5150_s_crop, -+ .g_crop = tvp5150_g_crop, -+ .cropcap = tvp5150_cropcap, - }; - - static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { -@@ -1083,6 +1192,15 @@ static int tvp5150_probe(struct i2c_clie - } - v4l2_ctrl_handler_setup(&core->hdl); - -+ /* Default is no cropping */ -+ core->rect.top = 0; -+ if (tvp5150_read_std(sd) & V4L2_STD_525_60) -+ core->rect.height = TVP5150_V_MAX_525_60; -+ else -+ core->rect.height = TVP5150_V_MAX_OTHERS; -+ core->rect.left = 0; -+ core->rect.width = TVP5150_H_MAX; -+ - if (debug > 1) - tvp5150_log_status(sd); - return 0; -@@ -1121,15 +1239,4 @@ static struct i2c_driver tvp5150_driver - .id_table = tvp5150_id, - }; - --static __init int init_tvp5150(void) --{ -- return i2c_add_driver(&tvp5150_driver); --} -- --static __exit void exit_tvp5150(void) --{ -- i2c_del_driver(&tvp5150_driver); --} -- --module_init(init_tvp5150); --module_exit(exit_tvp5150); -+module_i2c_driver(tvp5150_driver); -Index: linux-3.3.x86_64/drivers/media/video/tvp7002.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tvp7002.c -+++ linux-3.3.x86_64/drivers/media/video/tvp7002.c -@@ -1069,27 +1069,4 @@ static struct i2c_driver tvp7002_driver - .id_table = tvp7002_id, - }; - --/* -- * tvp7002_init - Initialize driver via I2C interface -- * -- * Register the TVP7002 driver. -- * Return 0 on success or error code on failure. -- */ --static int __init tvp7002_init(void) --{ -- return i2c_add_driver(&tvp7002_driver); --} -- --/* -- * tvp7002_exit - Remove driver via I2C interface -- * -- * Unregister the TVP7002 driver. -- * Returns nothing. -- */ --static void __exit tvp7002_exit(void) --{ -- i2c_del_driver(&tvp7002_driver); --} -- --module_init(tvp7002_init); --module_exit(tvp7002_exit); -+module_i2c_driver(tvp7002_driver); -Index: linux-3.3.x86_64/drivers/media/video/tw9910.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/tw9910.c -+++ linux-3.3.x86_64/drivers/media/video/tw9910.c -@@ -951,21 +951,7 @@ static struct i2c_driver tw9910_i2c_driv - .id_table = tw9910_id, - }; - --/* -- * module function -- */ --static int __init tw9910_module_init(void) --{ -- return i2c_add_driver(&tw9910_i2c_driver); --} -- --static void __exit tw9910_module_exit(void) --{ -- i2c_del_driver(&tw9910_i2c_driver); --} -- --module_init(tw9910_module_init); --module_exit(tw9910_module_exit); -+module_i2c_driver(tw9910_i2c_driver); - - MODULE_DESCRIPTION("SoC Camera driver for tw9910"); - MODULE_AUTHOR("Kuninori Morimoto"); -Index: linux-3.3.x86_64/drivers/media/video/upd64031a.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/upd64031a.c -+++ linux-3.3.x86_64/drivers/media/video/upd64031a.c -@@ -271,15 +271,4 @@ static struct i2c_driver upd64031a_drive - .id_table = upd64031a_id, - }; - --static __init int init_upd64031a(void) --{ -- return i2c_add_driver(&upd64031a_driver); --} -- --static __exit void exit_upd64031a(void) --{ -- i2c_del_driver(&upd64031a_driver); --} -- --module_init(init_upd64031a); --module_exit(exit_upd64031a); -+module_i2c_driver(upd64031a_driver); -Index: linux-3.3.x86_64/drivers/media/video/upd64083.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/upd64083.c -+++ linux-3.3.x86_64/drivers/media/video/upd64083.c -@@ -243,15 +243,4 @@ static struct i2c_driver upd64083_driver - .id_table = upd64083_id, - }; - --static __init int init_upd64083(void) --{ -- return i2c_add_driver(&upd64083_driver); --} -- --static __exit void exit_upd64083(void) --{ -- i2c_del_driver(&upd64083_driver); --} -- --module_init(init_upd64083); --module_exit(exit_upd64083); -+module_i2c_driver(upd64083_driver); -Index: linux-3.3.x86_64/drivers/media/video/vp27smpx.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/vp27smpx.c -+++ linux-3.3.x86_64/drivers/media/video/vp27smpx.c -@@ -208,15 +208,4 @@ static struct i2c_driver vp27smpx_driver - .id_table = vp27smpx_id, - }; - --static __init int init_vp27smpx(void) --{ -- return i2c_add_driver(&vp27smpx_driver); --} -- --static __exit void exit_vp27smpx(void) --{ -- i2c_del_driver(&vp27smpx_driver); --} -- --module_init(init_vp27smpx); --module_exit(exit_vp27smpx); -+module_i2c_driver(vp27smpx_driver); -Index: linux-3.3.x86_64/drivers/media/video/vpx3220.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/vpx3220.c -+++ linux-3.3.x86_64/drivers/media/video/vpx3220.c -@@ -588,15 +588,4 @@ static struct i2c_driver vpx3220_driver - .id_table = vpx3220_id, - }; - --static __init int init_vpx3220(void) --{ -- return i2c_add_driver(&vpx3220_driver); --} -- --static __exit void exit_vpx3220(void) --{ -- i2c_del_driver(&vpx3220_driver); --} -- --module_init(init_vpx3220); --module_exit(exit_vpx3220); -+module_i2c_driver(vpx3220_driver); -Index: linux-3.3.x86_64/drivers/media/video/wm8739.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/wm8739.c -+++ linux-3.3.x86_64/drivers/media/video/wm8739.c -@@ -291,15 +291,4 @@ static struct i2c_driver wm8739_driver = - .id_table = wm8739_id, - }; - --static __init int init_wm8739(void) --{ -- return i2c_add_driver(&wm8739_driver); --} -- --static __exit void exit_wm8739(void) --{ -- i2c_del_driver(&wm8739_driver); --} -- --module_init(init_wm8739); --module_exit(exit_wm8739); -+module_i2c_driver(wm8739_driver); -Index: linux-3.3.x86_64/drivers/media/video/wm8775.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/wm8775.c -+++ linux-3.3.x86_64/drivers/media/video/wm8775.c -@@ -339,15 +339,4 @@ static struct i2c_driver wm8775_driver = - .id_table = wm8775_id, - }; - --static __init int init_wm8775(void) --{ -- return i2c_add_driver(&wm8775_driver); --} -- --static __exit void exit_wm8775(void) --{ -- i2c_del_driver(&wm8775_driver); --} -- --module_init(init_wm8775); --module_exit(exit_wm8775); -+module_i2c_driver(wm8775_driver); -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe-priv.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/it913x-fe-priv.h -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe-priv.h -@@ -201,6 +201,11 @@ fe_modulation_t fe_con[] = { - QAM_64, - }; - -+enum { -+ PRIORITY_HIGH = 0, /* High-priority stream */ -+ PRIORITY_LOW, /* Low-priority stream */ -+}; -+ - /* Standard demodulator functions */ - static struct it913xset set_solo_fe[] = { - {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/it913x-fe.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe.c -@@ -57,6 +57,7 @@ struct it913x_fe_state { - u32 frequency; - fe_modulation_t constellation; - fe_transmit_mode_t transmission_mode; -+ u8 priority; - u32 crystalFrequency; - u32 adcFrequency; - u8 tuner_type; -@@ -500,19 +501,87 @@ static int it913x_fe_read_status(struct - return 0; - } - -+/* FEC values based on fe_code_rate_t non supported values 0*/ -+int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88}; -+int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82}; -+int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76}; -+ -+static int it913x_get_signal_strength(struct dvb_frontend *fe) -+{ -+ struct dtv_frontend_properties *p = &fe->dtv_property_cache; -+ struct it913x_fe_state *state = fe->demodulator_priv; -+ u8 code_rate; -+ int ret, temp; -+ u8 lna_gain_os; -+ -+ ret = it913x_read_reg_u8(state, VAR_P_INBAND); -+ if (ret < 0) -+ return ret; -+ -+ /* VHF/UHF gain offset */ -+ if (state->frequency < 300000000) -+ lna_gain_os = 7; -+ else -+ lna_gain_os = 14; -+ -+ temp = (ret - 100) - lna_gain_os; -+ -+ if (state->priority == PRIORITY_HIGH) -+ code_rate = p->code_rate_HP; -+ else -+ code_rate = p->code_rate_LP; -+ -+ if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval)) -+ return -EINVAL; -+ -+ deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp); -+ -+ /* Apply FEC offset values*/ -+ switch (p->modulation) { -+ case QPSK: -+ temp -= it913x_qpsk_pval[code_rate]; -+ break; -+ case QAM_16: -+ temp -= it913x_16qam_pval[code_rate]; -+ break; -+ case QAM_64: -+ temp -= it913x_64qam_pval[code_rate]; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (temp < -15) -+ ret = 0; -+ else if ((-15 <= temp) && (temp < 0)) -+ ret = (2 * (temp + 15)) / 3; -+ else if ((0 <= temp) && (temp < 20)) -+ ret = 4 * temp + 10; -+ else if ((20 <= temp) && (temp < 35)) -+ ret = (2 * (temp - 20)) / 3 + 90; -+ else if (temp >= 35) -+ ret = 100; -+ -+ deb_info("Signal Strength :%d", ret); -+ -+ return ret; -+} -+ - static int it913x_fe_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) - { - struct it913x_fe_state *state = fe->demodulator_priv; -- int ret = it913x_read_reg_u8(state, SIGNAL_LEVEL); -- /*SIGNAL_LEVEL always returns 100%! so using FE_HAS_SIGNAL as switch*/ -- if (state->it913x_status & FE_HAS_SIGNAL) -- ret = (ret * 0xff) / 0x64; -- else -- ret = 0x0; -- ret |= ret << 0x8; -- *strength = ret; -- return 0; -+ int ret = 0; -+ if (state->config->read_slevel) { -+ if (state->it913x_status & FE_HAS_SIGNAL) -+ ret = it913x_read_reg_u8(state, SIGNAL_LEVEL); -+ } else -+ ret = it913x_get_signal_strength(fe); -+ -+ if (ret >= 0) -+ *strength = (u16)((u32)ret * 0xffff / 0x64); -+ -+ return (ret < 0) ? -ENODEV : 0; - } - - static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr) -@@ -606,6 +675,8 @@ static int it913x_fe_get_frontend(struct - if (reg[2] < 4) - p->hierarchy = fe_hi[reg[2]]; - -+ state->priority = reg[5]; -+ - p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; - p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; - -@@ -972,5 +1043,5 @@ static struct dvb_frontend_ops it913x_fe - - MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); - MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); --MODULE_VERSION("1.13"); -+MODULE_VERSION("1.15"); - MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/it913x-fe.h -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/it913x-fe.h -@@ -34,6 +34,8 @@ struct ite_config { - u8 tuner_id_1; - u8 dual_mode; - u8 adf; -+ /* option to read SIGNAL_LEVEL */ -+ u8 read_slevel; - }; - - #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \ -@@ -168,6 +170,8 @@ static inline struct dvb_frontend *it913 - #define EST_SIGNAL_LEVEL 0x004a - #define FREE_BAND 0x004b - #define SUSPEND_FLAG 0x004c -+#define VAR_P_INBAND 0x00f7 -+ - /* Build in tuner types */ - #define IT9137 0x38 - #define IT9135_38 0x38 -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/cx22702.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/cx22702.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/cx22702.c -@@ -502,10 +502,26 @@ static int cx22702_read_signal_strength( - u16 *signal_strength) - { - struct cx22702_state *state = fe->demodulator_priv; -+ u8 reg23; - -- u16 rs_ber; -- rs_ber = cx22702_readreg(state, 0x23); -- *signal_strength = (rs_ber << 8) | rs_ber; -+ /* -+ * Experience suggests that the strength signal register works as -+ * follows: -+ * - In the absence of signal, value is 0xff. -+ * - In the presence of a weak signal, bit 7 is set, not sure what -+ * the lower 7 bits mean. -+ * - In the presence of a strong signal, the register holds a 7-bit -+ * value (bit 7 is cleared), with greater values standing for -+ * weaker signals. -+ */ -+ reg23 = cx22702_readreg(state, 0x23); -+ if (reg23 & 0x80) { -+ *signal_strength = 0; -+ } else { -+ reg23 = ~reg23 & 0x7f; -+ /* Scale to 16 bit */ -+ *signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5); -+ } - - return 0; - } -Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-cards.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-cards.c -+++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-cards.c -@@ -353,6 +353,44 @@ static struct em28xx_reg_seq hauppauge_9 - }; - #endif - -+/* 1b80:e425 MaxMedia UB425-TC -+ * GPIO_6 - demod reset, 0=active -+ * GPIO_7 - LED, 0=active -+ */ -+static struct em28xx_reg_seq maxmedia_ub425_tc[] = { -+ {EM2874_R80_GPIO, 0x83, 0xff, 100}, -+ {EM2874_R80_GPIO, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */ -+ {EM2874_R80_GPIO, 0x43, 0xff, 000}, /* GPIO_7 = 0 */ -+ {-1, -1, -1, -1}, -+}; -+ -+/* 2304:0242 PCTV QuatroStick (510e) -+ * GPIO_2: decoder reset, 0=active -+ * GPIO_4: decoder suspend, 0=active -+ * GPIO_6: demod reset, 0=active -+ * GPIO_7: LED, 1=active -+ */ -+static struct em28xx_reg_seq pctv_510e[] = { -+ {EM2874_R80_GPIO, 0x10, 0xff, 100}, -+ {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ -+ {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ -+ { -1, -1, -1, -1}, -+}; -+ -+/* 2013:0251 PCTV QuatroStick nano (520e) -+ * GPIO_2: decoder reset, 0=active -+ * GPIO_4: decoder suspend, 0=active -+ * GPIO_6: demod reset, 0=active -+ * GPIO_7: LED, 1=active -+ */ -+static struct em28xx_reg_seq pctv_520e[] = { -+ {EM2874_R80_GPIO, 0x10, 0xff, 100}, -+ {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ -+ {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ -+ {EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */ -+ { -1, -1, -1, -1}, -+}; -+ - /* - * Board definitions - */ -@@ -1908,6 +1946,41 @@ struct em28xx_board em28xx_boards[] = { - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, -+ /* 1b80:e425 MaxMedia UB425-TC -+ * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */ -+ [EM2874_BOARD_MAXMEDIA_UB425_TC] = { -+ .name = "MaxMedia UB425-TC", -+ .tuner_type = TUNER_ABSENT, -+ .tuner_gpio = maxmedia_ub425_tc, -+ .has_dvb = 1, -+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | -+ EM28XX_I2C_CLK_WAIT_ENABLE | -+ EM28XX_I2C_FREQ_400_KHZ, -+ }, -+ /* 2304:0242 PCTV QuatroStick (510e) -+ * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ -+ [EM2884_BOARD_PCTV_510E] = { -+ .name = "PCTV QuatroStick (510e)", -+ .tuner_type = TUNER_ABSENT, -+ .tuner_gpio = pctv_510e, -+ .has_dvb = 1, -+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD, -+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | -+ EM28XX_I2C_CLK_WAIT_ENABLE | -+ EM28XX_I2C_FREQ_400_KHZ, -+ }, -+ /* 2013:0251 PCTV QuatroStick nano (520e) -+ * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */ -+ [EM2884_BOARD_PCTV_520E] = { -+ .name = "PCTV QuatroStick nano (520e)", -+ .tuner_type = TUNER_ABSENT, -+ .tuner_gpio = pctv_520e, -+ .has_dvb = 1, -+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD, -+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | -+ EM28XX_I2C_CLK_WAIT_ENABLE | -+ EM28XX_I2C_FREQ_400_KHZ, -+ }, - }; - const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); - -@@ -2059,6 +2132,12 @@ struct usb_device_id em28xx_id_table[] = - .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 }, - { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */ - .driver_info = EM2860_BOARD_EASYCAP }, -+ { USB_DEVICE(0x1b80, 0xe425), -+ .driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC }, -+ { USB_DEVICE(0x2304, 0x0242), -+ .driver_info = EM2884_BOARD_PCTV_510E }, -+ { USB_DEVICE(0x2013, 0x0251), -+ .driver_info = EM2884_BOARD_PCTV_520E }, - { }, - }; - MODULE_DEVICE_TABLE(usb, em28xx_id_table); -@@ -3122,7 +3201,6 @@ static int em28xx_usb_probe(struct usb_i - int i, nr; - const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; - char *speed; -- char descr[255] = ""; - - udev = usb_get_dev(interface_to_usbdev(interface)); - -@@ -3227,21 +3305,11 @@ static int em28xx_usb_probe(struct usb_i - speed = "unknown"; - } - -- if (udev->manufacturer) -- strlcpy(descr, udev->manufacturer, sizeof(descr)); -- -- if (udev->product) { -- if (*descr) -- strlcat(descr, " ", sizeof(descr)); -- strlcat(descr, udev->product, sizeof(descr)); -- } -- -- if (*descr) -- strlcat(descr, " ", sizeof(descr)); -- - printk(KERN_INFO DRIVER_NAME -- ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n", -- descr, -+ ": New device %s %s @ %s Mbps " -+ "(%04x:%04x, interface %d, class %d)\n", -+ udev->manufacturer ? udev->manufacturer : "", -+ udev->product ? udev->product : "", - speed, - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), -@@ -3307,6 +3375,17 @@ static int em28xx_usb_probe(struct usb_i - goto unlock_and_free; - } - -+ if (has_dvb) { -+ /* pre-allocate DVB isoc transfer buffers */ -+ retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE, -+ EM28XX_DVB_MAX_PACKETS, -+ EM28XX_DVB_NUM_BUFS, -+ dev->dvb_max_pkt_size); -+ if (retval) { -+ goto unlock_and_free; -+ } -+ } -+ - request_modules(dev); - - /* Should be the last thing to do, to avoid newer udev's to -@@ -3379,7 +3458,7 @@ static void em28xx_usb_disconnect(struct - video_device_node_name(dev->vdev)); - - dev->state |= DEV_MISCONFIGURED; -- em28xx_uninit_isoc(dev); -+ em28xx_uninit_isoc(dev, dev->mode); - dev->state |= DEV_DISCONNECTED; - wake_up_interruptible(&dev->wait_frame); - wake_up_interruptible(&dev->wait_stream); -@@ -3388,6 +3467,9 @@ static void em28xx_usb_disconnect(struct - em28xx_release_resources(dev); - } - -+ /* free DVB isoc buffers */ -+ em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE); -+ - mutex_unlock(&dev->lock); - - em28xx_close_extension(dev); -Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-core.c -+++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-core.c -@@ -666,6 +666,7 @@ int em28xx_capture_start(struct em28xx * - - return rc; - } -+EXPORT_SYMBOL_GPL(em28xx_capture_start); - - int em28xx_vbi_supported(struct em28xx *dev) - { -@@ -961,146 +962,192 @@ static void em28xx_irq_callback(struct u - /* - * Stop and Deallocate URBs - */ --void em28xx_uninit_isoc(struct em28xx *dev) -+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode) - { - struct urb *urb; -+ struct em28xx_usb_isoc_bufs *isoc_bufs; - int i; - -- em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); -+ em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode); -+ -+ if (mode == EM28XX_DIGITAL_MODE) -+ isoc_bufs = &dev->isoc_ctl.digital_bufs; -+ else -+ isoc_bufs = &dev->isoc_ctl.analog_bufs; - - dev->isoc_ctl.nfields = -1; -- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { -- urb = dev->isoc_ctl.urb[i]; -+ for (i = 0; i < isoc_bufs->num_bufs; i++) { -+ urb = isoc_bufs->urb[i]; - if (urb) { - if (!irqs_disabled()) - usb_kill_urb(urb); - else - usb_unlink_urb(urb); - -- if (dev->isoc_ctl.transfer_buffer[i]) { -+ if (isoc_bufs->transfer_buffer[i]) { - usb_free_coherent(dev->udev, - urb->transfer_buffer_length, -- dev->isoc_ctl.transfer_buffer[i], -+ isoc_bufs->transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); -- dev->isoc_ctl.urb[i] = NULL; -+ isoc_bufs->urb[i] = NULL; - } -- dev->isoc_ctl.transfer_buffer[i] = NULL; -+ isoc_bufs->transfer_buffer[i] = NULL; - } - -- kfree(dev->isoc_ctl.urb); -- kfree(dev->isoc_ctl.transfer_buffer); -+ kfree(isoc_bufs->urb); -+ kfree(isoc_bufs->transfer_buffer); - -- dev->isoc_ctl.urb = NULL; -- dev->isoc_ctl.transfer_buffer = NULL; -- dev->isoc_ctl.num_bufs = 0; -+ isoc_bufs->urb = NULL; -+ isoc_bufs->transfer_buffer = NULL; -+ isoc_bufs->num_bufs = 0; - - em28xx_capture_start(dev, 0); - } - EXPORT_SYMBOL_GPL(em28xx_uninit_isoc); - - /* -- * Allocate URBs and start IRQ -+ * Allocate URBs - */ --int em28xx_init_isoc(struct em28xx *dev, int max_packets, -- int num_bufs, int max_pkt_size, -- int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) -+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode, -+ int max_packets, int num_bufs, int max_pkt_size) - { -- struct em28xx_dmaqueue *dma_q = &dev->vidq; -- struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; -+ struct em28xx_usb_isoc_bufs *isoc_bufs; - int i; - int sb_size, pipe; - struct urb *urb; - int j, k; -- int rc; - -- em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); -+ em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode); -+ -+ if (mode == EM28XX_DIGITAL_MODE) -+ isoc_bufs = &dev->isoc_ctl.digital_bufs; -+ else -+ isoc_bufs = &dev->isoc_ctl.analog_bufs; - - /* De-allocates all pending stuff */ -- em28xx_uninit_isoc(dev); -+ em28xx_uninit_isoc(dev, mode); - -- dev->isoc_ctl.isoc_copy = isoc_copy; -- dev->isoc_ctl.num_bufs = num_bufs; -+ isoc_bufs->num_bufs = num_bufs; - -- dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); -- if (!dev->isoc_ctl.urb) { -+ isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); -+ if (!isoc_bufs->urb) { - em28xx_errdev("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - -- dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, -- GFP_KERNEL); -- if (!dev->isoc_ctl.transfer_buffer) { -+ isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs, -+ GFP_KERNEL); -+ if (!isoc_bufs->transfer_buffer) { - em28xx_errdev("cannot allocate memory for usb transfer\n"); -- kfree(dev->isoc_ctl.urb); -+ kfree(isoc_bufs->urb); - return -ENOMEM; - } - -- dev->isoc_ctl.max_pkt_size = max_pkt_size; -+ isoc_bufs->max_pkt_size = max_pkt_size; -+ isoc_bufs->num_packets = max_packets; - dev->isoc_ctl.vid_buf = NULL; - dev->isoc_ctl.vbi_buf = NULL; - -- sb_size = max_packets * dev->isoc_ctl.max_pkt_size; -+ sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size; - - /* allocate urbs and transfer buffers */ -- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { -- urb = usb_alloc_urb(max_packets, GFP_KERNEL); -+ for (i = 0; i < isoc_bufs->num_bufs; i++) { -+ urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL); - if (!urb) { - em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); -- em28xx_uninit_isoc(dev); -+ em28xx_uninit_isoc(dev, mode); - return -ENOMEM; - } -- dev->isoc_ctl.urb[i] = urb; -+ isoc_bufs->urb[i] = urb; - -- dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, -+ isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev, - sb_size, GFP_KERNEL, &urb->transfer_dma); -- if (!dev->isoc_ctl.transfer_buffer[i]) { -+ if (!isoc_bufs->transfer_buffer[i]) { - em28xx_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); -- em28xx_uninit_isoc(dev); -+ em28xx_uninit_isoc(dev, mode); - return -ENOMEM; - } -- memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); -+ memset(isoc_bufs->transfer_buffer[i], 0, sb_size); - - /* FIXME: this is a hack - should be - 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' - should also be using 'desc.bInterval' - */ - pipe = usb_rcvisocpipe(dev->udev, -- dev->mode == EM28XX_ANALOG_MODE ? -+ mode == EM28XX_ANALOG_MODE ? - EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL); - - usb_fill_int_urb(urb, dev->udev, pipe, -- dev->isoc_ctl.transfer_buffer[i], sb_size, -+ isoc_bufs->transfer_buffer[i], sb_size, - em28xx_irq_callback, dev, 1); - -- urb->number_of_packets = max_packets; -+ urb->number_of_packets = isoc_bufs->num_packets; - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - - k = 0; -- for (j = 0; j < max_packets; j++) { -+ for (j = 0; j < isoc_bufs->num_packets; j++) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = -- dev->isoc_ctl.max_pkt_size; -- k += dev->isoc_ctl.max_pkt_size; -+ isoc_bufs->max_pkt_size; -+ k += isoc_bufs->max_pkt_size; - } - } - -+ return 0; -+} -+EXPORT_SYMBOL_GPL(em28xx_alloc_isoc); -+ -+/* -+ * Allocate URBs and start IRQ -+ */ -+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode, -+ int max_packets, int num_bufs, int max_pkt_size, -+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) -+{ -+ struct em28xx_dmaqueue *dma_q = &dev->vidq; -+ struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; -+ struct em28xx_usb_isoc_bufs *isoc_bufs; -+ int i; -+ int rc; -+ int alloc; -+ -+ em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode); -+ -+ dev->isoc_ctl.isoc_copy = isoc_copy; -+ -+ if (mode == EM28XX_DIGITAL_MODE) { -+ isoc_bufs = &dev->isoc_ctl.digital_bufs; -+ /* no need to free/alloc isoc buffers in digital mode */ -+ alloc = 0; -+ } else { -+ isoc_bufs = &dev->isoc_ctl.analog_bufs; -+ alloc = 1; -+ } -+ -+ if (alloc) { -+ rc = em28xx_alloc_isoc(dev, mode, max_packets, -+ num_bufs, max_pkt_size); -+ if (rc) -+ return rc; -+ } -+ - init_waitqueue_head(&dma_q->wq); - init_waitqueue_head(&vbi_dma_q->wq); - - em28xx_capture_start(dev, 1); - - /* submit urbs and enables IRQ */ -- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { -- rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); -+ for (i = 0; i < isoc_bufs->num_bufs; i++) { -+ rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC); - if (rc) { - em28xx_err("submit of urb %i failed (error=%i)\n", i, - rc); -- em28xx_uninit_isoc(dev); -+ em28xx_uninit_isoc(dev, mode); - return rc; - } - } -Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-dvb.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-dvb.c -+++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-dvb.c -@@ -61,9 +61,6 @@ if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ - } while (0) - --#define EM28XX_DVB_NUM_BUFS 5 --#define EM28XX_DVB_MAX_PACKETS 64 -- - struct em28xx_dvb { - struct dvb_frontend *fe[2]; - -@@ -172,20 +169,21 @@ static int em28xx_start_streaming(struct - max_dvb_packet_size = dev->dvb_max_pkt_size; - if (max_dvb_packet_size < 0) - return max_dvb_packet_size; -- dprintk(1, "Using %d buffers each with %d bytes\n", -+ dprintk(1, "Using %d buffers each with %d x %d bytes\n", - EM28XX_DVB_NUM_BUFS, -+ EM28XX_DVB_MAX_PACKETS, - max_dvb_packet_size); - -- return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, -- EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, -- em28xx_dvb_isoc_copy); -+ return em28xx_init_isoc(dev, EM28XX_DIGITAL_MODE, -+ EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS, -+ max_dvb_packet_size, em28xx_dvb_isoc_copy); - } - - static int em28xx_stop_streaming(struct em28xx_dvb *dvb) - { - struct em28xx *dev = dvb->adapter.priv; - -- em28xx_uninit_isoc(dev); -+ em28xx_capture_start(dev, 0); - - em28xx_set_mode(dev, EM28XX_SUSPEND); - -@@ -327,6 +325,19 @@ struct drxk_config hauppauge_930c_drxk = - .chunk_size = 56, - }; - -+struct drxk_config maxmedia_ub425_tc_drxk = { -+ .adr = 0x29, -+ .single_master = 1, -+ .no_i2c_bridge = 1, -+}; -+ -+struct drxk_config pctv_520e_drxk = { -+ .adr = 0x29, -+ .single_master = 1, -+ .microcode_name = "dvb-demod-drxk-pctv.fw", -+ .chunk_size = 58, -+}; -+ - static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) - { - struct em28xx_dvb *dvb = fe->sec_priv; -@@ -460,6 +471,33 @@ static void terratec_h5_init(struct em28 - em28xx_gpio_set(dev, terratec_h5_end); - }; - -+static void pctv_520e_init(struct em28xx *dev) -+{ -+ /* -+ * Init TDA8295(?) analog demodulator. Looks like I2C traffic to -+ * digital demodulator and tuner are routed via TDA8295. -+ */ -+ int i; -+ struct { -+ unsigned char r[4]; -+ int len; -+ } regs[] = { -+ {{ 0x06, 0x02, 0x00, 0x31 }, 4}, -+ {{ 0x01, 0x02 }, 2}, -+ {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, -+ {{ 0x01, 0x00 }, 2}, -+ {{ 0x01, 0x00, 0xff, 0xaf }, 4}, -+ {{ 0x01, 0x00, 0x03, 0xa0 }, 4}, -+ {{ 0x01, 0x00 }, 2}, -+ {{ 0x01, 0x00, 0x73, 0xaf }, 4}, -+ }; -+ -+ dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */ -+ -+ for (i = 0; i < ARRAY_SIZE(regs); i++) -+ i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); -+}; -+ - static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) - { - /* Values extracted from a USB trace of the Terratec Windows driver */ -@@ -938,6 +976,48 @@ static int em28xx_dvb_init(struct em28xx - dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap, - &em28xx_a8293_config); - break; -+ case EM2874_BOARD_MAXMEDIA_UB425_TC: -+ /* attach demodulator */ -+ dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk, -+ &dev->i2c_adap); -+ -+ if (dvb->fe[0]) { -+ /* disable I2C-gate */ -+ dvb->fe[0]->ops.i2c_gate_ctrl = NULL; -+ -+ /* attach tuner */ -+ if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], -+ &dev->i2c_adap, 0x60)) { -+ dvb_frontend_detach(dvb->fe[0]); -+ result = -EINVAL; -+ goto out_free; -+ } -+ } -+ -+ /* TODO: we need drx-3913k firmware in order to support DVB-T */ -+ em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \ -+ "driver version\n"); -+ -+ break; -+ case EM2884_BOARD_PCTV_510E: -+ case EM2884_BOARD_PCTV_520E: -+ pctv_520e_init(dev); -+ -+ /* attach demodulator */ -+ dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk, -+ &dev->i2c_adap); -+ -+ if (dvb->fe[0]) { -+ /* attach tuner */ -+ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, -+ &dev->i2c_adap, -+ &em28xx_cxd2820r_tda18271_config)) { -+ dvb_frontend_detach(dvb->fe[0]); -+ result = -EINVAL; -+ goto out_free; -+ } -+ } -+ break; - default: - em28xx_errdev("/2: The frontend of your DVB/ATSC card" - " isn't supported yet\n"); -Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-video.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-video.c -+++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-video.c -@@ -760,17 +760,19 @@ buffer_prepare(struct videobuf_queue *vq - goto fail; - } - -- if (!dev->isoc_ctl.num_bufs) -+ if (!dev->isoc_ctl.analog_bufs.num_bufs) - urb_init = 1; - - if (urb_init) { - if (em28xx_vbi_supported(dev) == 1) -- rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, -+ rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE, -+ EM28XX_NUM_PACKETS, - EM28XX_NUM_BUFS, - dev->max_pkt_size, - em28xx_isoc_copy_vbi); - else -- rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, -+ rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE, -+ EM28XX_NUM_PACKETS, - EM28XX_NUM_BUFS, - dev->max_pkt_size, - em28xx_isoc_copy); -@@ -2267,7 +2269,7 @@ static int em28xx_v4l2_close(struct file - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); - - /* do this before setting alternate! */ -- em28xx_uninit_isoc(dev); -+ em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE); - em28xx_set_mode(dev, EM28XX_SUSPEND); - - /* set alternate 0 */ -Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx.h -+++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx.h -@@ -125,6 +125,9 @@ - #define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81 - #define EM2884_BOARD_CINERGY_HTC_STICK 82 - #define EM2860_BOARD_HT_VIDBOX_NW03 83 -+#define EM2874_BOARD_MAXMEDIA_UB425_TC 84 -+#define EM2884_BOARD_PCTV_510E 85 -+#define EM2884_BOARD_PCTV_520E 86 - - /* Limits minimum and default number of buffers */ - #define EM28XX_MIN_BUF 4 -@@ -151,12 +154,14 @@ - - /* number of buffers for isoc transfers */ - #define EM28XX_NUM_BUFS 5 -+#define EM28XX_DVB_NUM_BUFS 5 - - /* number of packets for each buffer - windows requests only 64 packets .. so we better do the same - this is what I found out for all alternate numbers there! - */ - #define EM28XX_NUM_PACKETS 64 -+#define EM28XX_DVB_MAX_PACKETS 64 - - #define EM28XX_INTERLACED_DEFAULT 1 - -@@ -197,10 +202,13 @@ enum em28xx_mode { - - struct em28xx; - --struct em28xx_usb_isoc_ctl { -+struct em28xx_usb_isoc_bufs { - /* max packet size of isoc transaction */ - int max_pkt_size; - -+ /* number of packets in each buffer */ -+ int num_packets; -+ - /* number of allocated urbs */ - int num_bufs; - -@@ -209,6 +217,14 @@ struct em28xx_usb_isoc_ctl { - - /* transfer buffers for isoc transfer */ - char **transfer_buffer; -+}; -+ -+struct em28xx_usb_isoc_ctl { -+ /* isoc transfer buffers for analog mode */ -+ struct em28xx_usb_isoc_bufs analog_bufs; -+ -+ /* isoc transfer buffers for digital mode */ -+ struct em28xx_usb_isoc_bufs digital_bufs; - - /* Last buffer command and region */ - u8 cmd; -@@ -600,9 +616,6 @@ struct em28xx { - unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ - int dvb_alt; /* alternate for DVB */ - unsigned int dvb_max_pkt_size; /* wMaxPacketSize for DVB */ -- struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ -- char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc -- transfer */ - char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ - - /* helper funcs that call usb_control_msg */ -@@ -676,10 +689,12 @@ int em28xx_vbi_supported(struct em28xx * - int em28xx_set_outfmt(struct em28xx *dev); - int em28xx_resolution_set(struct em28xx *dev); - int em28xx_set_alternate(struct em28xx *dev); --int em28xx_init_isoc(struct em28xx *dev, int max_packets, -- int num_bufs, int max_pkt_size, -+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode, -+ int max_packets, int num_bufs, int max_pkt_size); -+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode, -+ int max_packets, int num_bufs, int max_pkt_size, - int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); --void em28xx_uninit_isoc(struct em28xx *dev); -+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode); - int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); - int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); - int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); -Index: linux-3.3.x86_64/drivers/media/video/mx2_camera.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/mx2_camera.c -+++ linux-3.3.x86_64/drivers/media/video/mx2_camera.c -@@ -3,6 +3,7 @@ - * - * Copyright (C) 2008, Sascha Hauer, Pengutronix - * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography -+ * Copyright (C) 2012, Javier Martin, Vista Silicon S.L. - * - * 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 -@@ -18,6 +19,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -30,17 +32,14 @@ - - #include - #include --#include --#include -+#include -+#include - #include - #include - - #include - - #include --#ifdef CONFIG_MACH_MX27 --#include --#endif - #include - - #include -@@ -206,10 +205,23 @@ - #define PRP_INTR_LBOVF (1 << 7) - #define PRP_INTR_CH2OVF (1 << 8) - --#define mx27_camera_emma(pcdev) (cpu_is_mx27() && pcdev->use_emma) -+/* Resizing registers */ -+#define PRP_RZ_VALID_TBL_LEN(x) ((x) << 24) -+#define PRP_RZ_VALID_BILINEAR (1 << 31) - - #define MAX_VIDEO_MEM 16 - -+#define RESIZE_NUM_MIN 1 -+#define RESIZE_NUM_MAX 20 -+#define BC_COEF 3 -+#define SZ_COEF (1 << BC_COEF) -+ -+#define RESIZE_DIR_H 0 -+#define RESIZE_DIR_V 1 -+ -+#define RESIZE_ALGO_BILINEAR 0 -+#define RESIZE_ALGO_AVERAGING 1 -+ - struct mx2_prp_cfg { - int channel; - u32 in_fmt; -@@ -219,6 +231,13 @@ struct mx2_prp_cfg { - u32 irq_flags; - }; - -+/* prp resizing parameters */ -+struct emma_prp_resize { -+ int algo; /* type of algorithm used */ -+ int len; /* number of coefficients */ -+ unsigned char s[RESIZE_NUM_MAX]; /* table of coefficients */ -+}; -+ - /* prp configuration for a client-host fmt pair */ - struct mx2_fmt_cfg { - enum v4l2_mbus_pixelcode in_fmt; -@@ -226,6 +245,26 @@ struct mx2_fmt_cfg { - struct mx2_prp_cfg cfg; - }; - -+enum mx2_buffer_state { -+ MX2_STATE_QUEUED, -+ MX2_STATE_ACTIVE, -+ MX2_STATE_DONE, -+}; -+ -+struct mx2_buf_internal { -+ struct list_head queue; -+ int bufnum; -+ bool discard; -+}; -+ -+/* buffer for one video frame */ -+struct mx2_buffer { -+ /* common v4l buffer stuff -- must be first */ -+ struct vb2_buffer vb; -+ enum mx2_buffer_state state; -+ struct mx2_buf_internal internal; -+}; -+ - struct mx2_camera_dev { - struct device *dev; - struct soc_camera_host soc_host; -@@ -242,6 +281,7 @@ struct mx2_camera_dev { - - struct list_head capture; - struct list_head active_bufs; -+ struct list_head discard; - - spinlock_t lock; - -@@ -250,26 +290,23 @@ struct mx2_camera_dev { - struct mx2_buffer *fb1_active; - struct mx2_buffer *fb2_active; - -- int use_emma; -- - u32 csicr1; - -+ struct mx2_buf_internal buf_discard[2]; - void *discard_buffer; - dma_addr_t discard_buffer_dma; - size_t discard_size; - struct mx2_fmt_cfg *emma_prp; -+ struct emma_prp_resize resizing[2]; -+ unsigned int s_width, s_height; - u32 frame_count; -+ struct vb2_alloc_ctx *alloc_ctx; - }; - --/* buffer for one video frame */ --struct mx2_buffer { -- /* common v4l buffer stuff -- must be first */ -- struct videobuf_buffer vb; -- -- enum v4l2_mbus_pixelcode code; -- -- int bufnum; --}; -+static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf) -+{ -+ return container_of(int_buf, struct mx2_buffer, internal); -+} - - static struct mx2_fmt_cfg mx27_emma_prp_table[] = { - /* -@@ -324,13 +361,36 @@ static struct mx2_fmt_cfg *mx27_emma_prp - return &mx27_emma_prp_table[0]; - }; - -+static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev, -+ unsigned long phys, int bufnum) -+{ -+ struct mx2_fmt_cfg *prp = pcdev->emma_prp; -+ -+ if (prp->cfg.channel == 1) { -+ writel(phys, pcdev->base_emma + -+ PRP_DEST_RGB1_PTR + 4 * bufnum); -+ } else { -+ writel(phys, pcdev->base_emma + -+ PRP_DEST_Y_PTR - 0x14 * bufnum); -+ if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { -+ u32 imgsize = pcdev->icd->user_height * -+ pcdev->icd->user_width; -+ -+ writel(phys + imgsize, pcdev->base_emma + -+ PRP_DEST_CB_PTR - 0x14 * bufnum); -+ writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + -+ PRP_DEST_CR_PTR - 0x14 * bufnum); -+ } -+ } -+} -+ - static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) - { - unsigned long flags; - - clk_disable(pcdev->clk_csi); - writel(0, pcdev->base_csi + CSICR1); -- if (mx27_camera_emma(pcdev)) { -+ if (cpu_is_mx27()) { - writel(0, pcdev->base_emma + PRP_CNTL); - } else if (cpu_is_mx25()) { - spin_lock_irqsave(&pcdev->lock, flags); -@@ -362,7 +422,7 @@ static int mx2_camera_add_device(struct - - csicr1 = CSICR1_MCLKEN; - -- if (mx27_camera_emma(pcdev)) { -+ if (cpu_is_mx27()) { - csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC | - CSICR1_RXFF_LEVEL(0); - } else if (cpu_is_mx27()) -@@ -392,56 +452,13 @@ static void mx2_camera_remove_device(str - - mx2_camera_deactivate(pcdev); - -- if (pcdev->discard_buffer) { -- dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size, -- pcdev->discard_buffer, -- pcdev->discard_buffer_dma); -- pcdev->discard_buffer = NULL; -- } -- - pcdev->icd = NULL; - } - --#ifdef CONFIG_MACH_MX27 --static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev) --{ -- u32 tmp; -- -- imx_dma_enable(pcdev->dma); -- -- tmp = readl(pcdev->base_csi + CSICR1); -- tmp |= CSICR1_RF_OR_INTEN; -- writel(tmp, pcdev->base_csi + CSICR1); --} -- --static irqreturn_t mx27_camera_irq(int irq_csi, void *data) --{ -- struct mx2_camera_dev *pcdev = data; -- u32 status = readl(pcdev->base_csi + CSISR); -- -- if (status & CSISR_SOF_INT && pcdev->active) { -- u32 tmp; -- -- tmp = readl(pcdev->base_csi + CSICR1); -- writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1); -- mx27_camera_dma_enable(pcdev); -- } -- -- writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR); -- -- return IRQ_HANDLED; --} --#else --static irqreturn_t mx27_camera_irq(int irq_csi, void *data) --{ -- return IRQ_NONE; --} --#endif /* CONFIG_MACH_MX27 */ -- - static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb, - int state) - { -- struct videobuf_buffer *vb; -+ struct vb2_buffer *vb; - struct mx2_buffer *buf; - struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active : - &pcdev->fb2_active; -@@ -454,25 +471,24 @@ static void mx25_camera_frame_done(struc - goto out; - - vb = &(*fb_active)->vb; -- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, -- vb, vb->baddr, vb->bsize); -- -- vb->state = state; -- do_gettimeofday(&vb->ts); -- vb->field_count++; -+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, -+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - -- wake_up(&vb->done); -+ do_gettimeofday(&vb->v4l2_buf.timestamp); -+ vb->v4l2_buf.sequence++; -+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - - if (list_empty(&pcdev->capture)) { - buf = NULL; - writel(0, pcdev->base_csi + fb_reg); - } else { -- buf = list_entry(pcdev->capture.next, struct mx2_buffer, -- vb.queue); -+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer, -+ internal.queue); - vb = &buf->vb; -- list_del(&vb->queue); -- vb->state = VIDEOBUF_ACTIVE; -- writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg); -+ list_del(&buf->internal.queue); -+ buf->state = MX2_STATE_ACTIVE; -+ writel(vb2_dma_contig_plane_dma_addr(vb, 0), -+ pcdev->base_csi + fb_reg); - } - - *fb_active = buf; -@@ -487,9 +503,9 @@ static irqreturn_t mx25_camera_irq(int i - u32 status = readl(pcdev->base_csi + CSISR); - - if (status & CSISR_DMA_TSF_FB1_INT) -- mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE); -+ mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE); - else if (status & CSISR_DMA_TSF_FB2_INT) -- mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE); -+ mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE); - - /* FIXME: handle CSISR_RFF_OR_INT */ - -@@ -501,59 +517,50 @@ static irqreturn_t mx25_camera_irq(int i - /* - * Videobuf operations - */ --static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, -- unsigned int *size) -+static int mx2_videobuf_setup(struct vb2_queue *vq, -+ const struct v4l2_format *fmt, -+ unsigned int *count, unsigned int *num_planes, -+ unsigned int sizes[], void *alloc_ctxs[]) - { -- struct soc_camera_device *icd = vq->priv_data; -+ struct soc_camera_device *icd = soc_camera_from_vb2q(vq); -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct mx2_camera_dev *pcdev = ici->priv; - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - -- dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size); -+ dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); -+ -+ /* TODO: support for VIDIOC_CREATE_BUFS not ready */ -+ if (fmt != NULL) -+ return -ENOTTY; - - if (bytes_per_line < 0) - return bytes_per_line; - -- *size = bytes_per_line * icd->user_height; -+ alloc_ctxs[0] = pcdev->alloc_ctx; -+ -+ sizes[0] = bytes_per_line * icd->user_height; - - if (0 == *count) - *count = 32; -- if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) -- *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; -+ if (!*num_planes && -+ sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) -+ *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0]; - -- return 0; --} -- --static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf) --{ -- struct soc_camera_device *icd = vq->priv_data; -- struct videobuf_buffer *vb = &buf->vb; -+ *num_planes = 1; - -- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, -- vb, vb->baddr, vb->bsize); -- -- /* -- * This waits until this buffer is out of danger, i.e., until it is no -- * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE -- */ -- videobuf_waiton(vq, vb, 0, 0); -- -- videobuf_dma_contig_free(vq, vb); -- dev_dbg(icd->parent, "%s freed\n", __func__); -- -- vb->state = VIDEOBUF_NEEDS_INIT; -+ return 0; - } - --static int mx2_videobuf_prepare(struct videobuf_queue *vq, -- struct videobuf_buffer *vb, enum v4l2_field field) -+static int mx2_videobuf_prepare(struct vb2_buffer *vb) - { -- struct soc_camera_device *icd = vq->priv_data; -- struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); -+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, - icd->current_fmt->host_fmt); - int ret = 0; - -- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, -- vb, vb->baddr, vb->bsize); -+ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, -+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - - if (bytes_per_line < 0) - return bytes_per_line; -@@ -563,99 +570,58 @@ static int mx2_videobuf_prepare(struct v - * This can be useful if you want to see if we actually fill - * the buffer with something - */ -- memset((void *)vb->baddr, 0xaa, vb->bsize); -+ memset((void *)vb2_plane_vaddr(vb, 0), -+ 0xaa, vb2_get_plane_payload(vb, 0)); - #endif - -- if (buf->code != icd->current_fmt->code || -- vb->width != icd->user_width || -- vb->height != icd->user_height || -- vb->field != field) { -- buf->code = icd->current_fmt->code; -- vb->width = icd->user_width; -- vb->height = icd->user_height; -- vb->field = field; -- vb->state = VIDEOBUF_NEEDS_INIT; -- } -- -- vb->size = bytes_per_line * vb->height; -- if (vb->baddr && vb->bsize < vb->size) { -+ vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height); -+ if (vb2_plane_vaddr(vb, 0) && -+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { - ret = -EINVAL; - goto out; - } - -- if (vb->state == VIDEOBUF_NEEDS_INIT) { -- ret = videobuf_iolock(vq, vb, NULL); -- if (ret) -- goto fail; -- -- vb->state = VIDEOBUF_PREPARED; -- } -- - return 0; - --fail: -- free_buffer(vq, buf); - out: - return ret; - } - --static void mx2_videobuf_queue(struct videobuf_queue *vq, -- struct videobuf_buffer *vb) -+static void mx2_videobuf_queue(struct vb2_buffer *vb) - { -- struct soc_camera_device *icd = vq->priv_data; -+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = - to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); - unsigned long flags; - -- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, -- vb, vb->baddr, vb->bsize); -+ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, -+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - - spin_lock_irqsave(&pcdev->lock, flags); - -- vb->state = VIDEOBUF_QUEUED; -- list_add_tail(&vb->queue, &pcdev->capture); -- -- if (mx27_camera_emma(pcdev)) { -- goto out; --#ifdef CONFIG_MACH_MX27 -- } else if (cpu_is_mx27()) { -- int ret; -- -- if (pcdev->active == NULL) { -- ret = imx_dma_setup_single(pcdev->dma, -- videobuf_to_dma_contig(vb), vb->size, -- (u32)pcdev->base_dma + 0x10, -- DMA_MODE_READ); -- if (ret) { -- vb->state = VIDEOBUF_ERROR; -- wake_up(&vb->done); -- goto out; -- } -+ buf->state = MX2_STATE_QUEUED; -+ list_add_tail(&buf->internal.queue, &pcdev->capture); - -- vb->state = VIDEOBUF_ACTIVE; -- pcdev->active = buf; -- } --#endif -- } else { /* cpu_is_mx25() */ -+ if (cpu_is_mx25()) { - u32 csicr3, dma_inten = 0; - - if (pcdev->fb1_active == NULL) { -- writel(videobuf_to_dma_contig(vb), -+ writel(vb2_dma_contig_plane_dma_addr(vb, 0), - pcdev->base_csi + CSIDMASA_FB1); - pcdev->fb1_active = buf; - dma_inten = CSICR1_FB1_DMA_INTEN; - } else if (pcdev->fb2_active == NULL) { -- writel(videobuf_to_dma_contig(vb), -+ writel(vb2_dma_contig_plane_dma_addr(vb, 0), - pcdev->base_csi + CSIDMASA_FB2); - pcdev->fb2_active = buf; - dma_inten = CSICR1_FB2_DMA_INTEN; - } - - if (dma_inten) { -- list_del(&vb->queue); -- vb->state = VIDEOBUF_ACTIVE; -+ list_del(&buf->internal.queue); -+ buf->state = MX2_STATE_ACTIVE; - - csicr3 = readl(pcdev->base_csi + CSICR3); - -@@ -674,36 +640,31 @@ static void mx2_videobuf_queue(struct vi - } - } - --out: - spin_unlock_irqrestore(&pcdev->lock, flags); - } - --static void mx2_videobuf_release(struct videobuf_queue *vq, -- struct videobuf_buffer *vb) -+static void mx2_videobuf_release(struct vb2_buffer *vb) - { -- struct soc_camera_device *icd = vq->priv_data; -+ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct mx2_camera_dev *pcdev = ici->priv; - struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb); - unsigned long flags; - - #ifdef DEBUG -- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, -- vb, vb->baddr, vb->bsize); -+ dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, -+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - -- switch (vb->state) { -- case VIDEOBUF_ACTIVE: -+ switch (buf->state) { -+ case MX2_STATE_ACTIVE: - dev_info(icd->parent, "%s (active)\n", __func__); - break; -- case VIDEOBUF_QUEUED: -+ case MX2_STATE_QUEUED: - dev_info(icd->parent, "%s (queued)\n", __func__); - break; -- case VIDEOBUF_PREPARED: -- dev_info(icd->parent, "%s (prepared)\n", __func__); -- break; - default: - dev_info(icd->parent, "%s (unknown) %d\n", __func__, -- vb->state); -+ buf->state); - break; - } - #endif -@@ -717,11 +678,9 @@ static void mx2_videobuf_release(struct - * state. This requires a specific handling for each of the these DMA - * types. - */ -+ - spin_lock_irqsave(&pcdev->lock, flags); -- if (vb->state == VIDEOBUF_QUEUED) { -- list_del(&vb->queue); -- vb->state = VIDEOBUF_ERROR; -- } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) { -+ if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) { - if (pcdev->fb1_active == buf) { - pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; - writel(0, pcdev->base_csi + CSIDMASA_FB1); -@@ -732,30 +691,260 @@ static void mx2_videobuf_release(struct - pcdev->fb2_active = NULL; - } - writel(pcdev->csicr1, pcdev->base_csi + CSICR1); -- vb->state = VIDEOBUF_ERROR; - } - spin_unlock_irqrestore(&pcdev->lock, flags); -+} -+ -+static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, -+ int bytesperline) -+{ -+ struct soc_camera_host *ici = -+ to_soc_camera_host(icd->parent); -+ struct mx2_camera_dev *pcdev = ici->priv; -+ struct mx2_fmt_cfg *prp = pcdev->emma_prp; -+ -+ writel((pcdev->s_width << 16) | pcdev->s_height, -+ pcdev->base_emma + PRP_SRC_FRAME_SIZE); -+ writel(prp->cfg.src_pixel, -+ pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); -+ if (prp->cfg.channel == 1) { -+ writel((icd->user_width << 16) | icd->user_height, -+ pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); -+ writel(bytesperline, -+ pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); -+ writel(prp->cfg.ch1_pixel, -+ pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); -+ } else { /* channel 2 */ -+ writel((icd->user_width << 16) | icd->user_height, -+ pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); -+ } -+ -+ /* Enable interrupts */ -+ writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); -+} -+ -+static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev) -+{ -+ int dir; -+ -+ for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { -+ unsigned char *s = pcdev->resizing[dir].s; -+ int len = pcdev->resizing[dir].len; -+ unsigned int coeff[2] = {0, 0}; -+ unsigned int valid = 0; -+ int i; -+ -+ if (len == 0) -+ continue; -+ -+ for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) { -+ int j; -+ -+ j = i > 9 ? 1 : 0; -+ coeff[j] = (coeff[j] << BC_COEF) | -+ (s[i] & (SZ_COEF - 1)); -+ -+ if (i == 5 || i == 15) -+ coeff[j] <<= 1; -+ -+ valid = (valid << 1) | (s[i] >> BC_COEF); -+ } -+ -+ valid |= PRP_RZ_VALID_TBL_LEN(len); -+ -+ if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR) -+ valid |= PRP_RZ_VALID_BILINEAR; -+ -+ if (pcdev->emma_prp->cfg.channel == 1) { -+ if (dir == RESIZE_DIR_H) { -+ writel(coeff[0], pcdev->base_emma + -+ PRP_CH1_RZ_HORI_COEF1); -+ writel(coeff[1], pcdev->base_emma + -+ PRP_CH1_RZ_HORI_COEF2); -+ writel(valid, pcdev->base_emma + -+ PRP_CH1_RZ_HORI_VALID); -+ } else { -+ writel(coeff[0], pcdev->base_emma + -+ PRP_CH1_RZ_VERT_COEF1); -+ writel(coeff[1], pcdev->base_emma + -+ PRP_CH1_RZ_VERT_COEF2); -+ writel(valid, pcdev->base_emma + -+ PRP_CH1_RZ_VERT_VALID); -+ } -+ } else { -+ if (dir == RESIZE_DIR_H) { -+ writel(coeff[0], pcdev->base_emma + -+ PRP_CH2_RZ_HORI_COEF1); -+ writel(coeff[1], pcdev->base_emma + -+ PRP_CH2_RZ_HORI_COEF2); -+ writel(valid, pcdev->base_emma + -+ PRP_CH2_RZ_HORI_VALID); -+ } else { -+ writel(coeff[0], pcdev->base_emma + -+ PRP_CH2_RZ_VERT_COEF1); -+ writel(coeff[1], pcdev->base_emma + -+ PRP_CH2_RZ_VERT_COEF2); -+ writel(valid, pcdev->base_emma + -+ PRP_CH2_RZ_VERT_VALID); -+ } -+ } -+ } -+} -+ -+static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) -+{ -+ struct soc_camera_device *icd = soc_camera_from_vb2q(q); -+ struct soc_camera_host *ici = -+ to_soc_camera_host(icd->parent); -+ struct mx2_camera_dev *pcdev = ici->priv; -+ struct mx2_fmt_cfg *prp = pcdev->emma_prp; -+ struct vb2_buffer *vb; -+ struct mx2_buffer *buf; -+ unsigned long phys; -+ int bytesperline; -+ -+ if (cpu_is_mx27()) { -+ unsigned long flags; -+ if (count < 2) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&pcdev->lock, flags); -+ -+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer, -+ internal.queue); -+ buf->internal.bufnum = 0; -+ vb = &buf->vb; -+ buf->state = MX2_STATE_ACTIVE; -+ -+ phys = vb2_dma_contig_plane_dma_addr(vb, 0); -+ mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); -+ list_move_tail(pcdev->capture.next, &pcdev->active_bufs); -+ -+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer, -+ internal.queue); -+ buf->internal.bufnum = 1; -+ vb = &buf->vb; -+ buf->state = MX2_STATE_ACTIVE; -+ -+ phys = vb2_dma_contig_plane_dma_addr(vb, 0); -+ mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); -+ list_move_tail(pcdev->capture.next, &pcdev->active_bufs); -+ -+ bytesperline = soc_mbus_bytes_per_line(icd->user_width, -+ icd->current_fmt->host_fmt); -+ if (bytesperline < 0) -+ return bytesperline; -+ -+ /* -+ * I didn't manage to properly enable/disable the prp -+ * on a per frame basis during running transfers, -+ * thus we allocate a buffer here and use it to -+ * discard frames when no buffer is available. -+ * Feel free to work on this ;) -+ */ -+ pcdev->discard_size = icd->user_height * bytesperline; -+ pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, -+ pcdev->discard_size, &pcdev->discard_buffer_dma, -+ GFP_KERNEL); -+ if (!pcdev->discard_buffer) -+ return -ENOMEM; -+ -+ pcdev->buf_discard[0].discard = true; -+ list_add_tail(&pcdev->buf_discard[0].queue, -+ &pcdev->discard); -+ -+ pcdev->buf_discard[1].discard = true; -+ list_add_tail(&pcdev->buf_discard[1].queue, -+ &pcdev->discard); -+ -+ mx2_prp_resize_commit(pcdev); -+ -+ mx27_camera_emma_buf_init(icd, bytesperline); -+ -+ if (prp->cfg.channel == 1) { -+ writel(PRP_CNTL_CH1EN | -+ PRP_CNTL_CSIEN | -+ prp->cfg.in_fmt | -+ prp->cfg.out_fmt | -+ PRP_CNTL_CH1_LEN | -+ PRP_CNTL_CH1BYP | -+ PRP_CNTL_CH1_TSKIP(0) | -+ PRP_CNTL_IN_TSKIP(0), -+ pcdev->base_emma + PRP_CNTL); -+ } else { -+ writel(PRP_CNTL_CH2EN | -+ PRP_CNTL_CSIEN | -+ prp->cfg.in_fmt | -+ prp->cfg.out_fmt | -+ PRP_CNTL_CH2_LEN | -+ PRP_CNTL_CH2_TSKIP(0) | -+ PRP_CNTL_IN_TSKIP(0), -+ pcdev->base_emma + PRP_CNTL); -+ } -+ spin_unlock_irqrestore(&pcdev->lock, flags); -+ } -+ -+ return 0; -+} -+ -+static int mx2_stop_streaming(struct vb2_queue *q) -+{ -+ struct soc_camera_device *icd = soc_camera_from_vb2q(q); -+ struct soc_camera_host *ici = -+ to_soc_camera_host(icd->parent); -+ struct mx2_camera_dev *pcdev = ici->priv; -+ struct mx2_fmt_cfg *prp = pcdev->emma_prp; -+ unsigned long flags; -+ void *b; -+ u32 cntl; -+ -+ if (cpu_is_mx27()) { -+ spin_lock_irqsave(&pcdev->lock, flags); -+ -+ cntl = readl(pcdev->base_emma + PRP_CNTL); -+ if (prp->cfg.channel == 1) { -+ writel(cntl & ~PRP_CNTL_CH1EN, -+ pcdev->base_emma + PRP_CNTL); -+ } else { -+ writel(cntl & ~PRP_CNTL_CH2EN, -+ pcdev->base_emma + PRP_CNTL); -+ } -+ INIT_LIST_HEAD(&pcdev->capture); -+ INIT_LIST_HEAD(&pcdev->active_bufs); -+ INIT_LIST_HEAD(&pcdev->discard); -+ -+ b = pcdev->discard_buffer; -+ pcdev->discard_buffer = NULL; -+ -+ spin_unlock_irqrestore(&pcdev->lock, flags); -+ -+ dma_free_coherent(ici->v4l2_dev.dev, -+ pcdev->discard_size, b, pcdev->discard_buffer_dma); -+ } - -- free_buffer(vq, buf); -+ return 0; - } - --static struct videobuf_queue_ops mx2_videobuf_ops = { -- .buf_setup = mx2_videobuf_setup, -- .buf_prepare = mx2_videobuf_prepare, -- .buf_queue = mx2_videobuf_queue, -- .buf_release = mx2_videobuf_release, -+static struct vb2_ops mx2_videobuf_ops = { -+ .queue_setup = mx2_videobuf_setup, -+ .buf_prepare = mx2_videobuf_prepare, -+ .buf_queue = mx2_videobuf_queue, -+ .buf_cleanup = mx2_videobuf_release, -+ .start_streaming = mx2_start_streaming, -+ .stop_streaming = mx2_stop_streaming, - }; - --static void mx2_camera_init_videobuf(struct videobuf_queue *q, -+static int mx2_camera_init_videobuf(struct vb2_queue *q, - struct soc_camera_device *icd) - { -- struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -- struct mx2_camera_dev *pcdev = ici->priv; -+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ q->io_modes = VB2_MMAP | VB2_USERPTR; -+ q->drv_priv = icd; -+ q->ops = &mx2_videobuf_ops; -+ q->mem_ops = &vb2_dma_contig_memops; -+ q->buf_struct_size = sizeof(struct mx2_buffer); - -- videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev, -- &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, -- V4L2_FIELD_NONE, sizeof(struct mx2_buffer), -- icd, &icd->video_lock); -+ return vb2_queue_init(q); - } - - #define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ -@@ -785,82 +974,6 @@ static int mx27_camera_emma_prp_reset(st - return -ETIMEDOUT; - } - --static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, -- int bytesperline) --{ -- struct soc_camera_host *ici = -- to_soc_camera_host(icd->parent); -- struct mx2_camera_dev *pcdev = ici->priv; -- struct mx2_fmt_cfg *prp = pcdev->emma_prp; -- u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; -- -- if (prp->cfg.channel == 1) { -- writel(pcdev->discard_buffer_dma, -- pcdev->base_emma + PRP_DEST_RGB1_PTR); -- writel(pcdev->discard_buffer_dma, -- pcdev->base_emma + PRP_DEST_RGB2_PTR); -- -- writel(PRP_CNTL_CH1EN | -- PRP_CNTL_CSIEN | -- prp->cfg.in_fmt | -- prp->cfg.out_fmt | -- PRP_CNTL_CH1_LEN | -- PRP_CNTL_CH1BYP | -- PRP_CNTL_CH1_TSKIP(0) | -- PRP_CNTL_IN_TSKIP(0), -- pcdev->base_emma + PRP_CNTL); -- -- writel((icd->user_width << 16) | icd->user_height, -- pcdev->base_emma + PRP_SRC_FRAME_SIZE); -- writel((icd->user_width << 16) | icd->user_height, -- pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); -- writel(bytesperline, -- pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); -- writel(prp->cfg.src_pixel, -- pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); -- writel(prp->cfg.ch1_pixel, -- pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); -- } else { /* channel 2 */ -- writel(pcdev->discard_buffer_dma, -- pcdev->base_emma + PRP_DEST_Y_PTR); -- writel(pcdev->discard_buffer_dma, -- pcdev->base_emma + PRP_SOURCE_Y_PTR); -- -- if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { -- writel(pcdev->discard_buffer_dma + imgsize, -- pcdev->base_emma + PRP_DEST_CB_PTR); -- writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), -- pcdev->base_emma + PRP_DEST_CR_PTR); -- writel(pcdev->discard_buffer_dma + imgsize, -- pcdev->base_emma + PRP_SOURCE_CB_PTR); -- writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), -- pcdev->base_emma + PRP_SOURCE_CR_PTR); -- } -- -- writel(PRP_CNTL_CH2EN | -- PRP_CNTL_CSIEN | -- prp->cfg.in_fmt | -- prp->cfg.out_fmt | -- PRP_CNTL_CH2_LEN | -- PRP_CNTL_CH2_TSKIP(0) | -- PRP_CNTL_IN_TSKIP(0), -- pcdev->base_emma + PRP_CNTL); -- -- writel((icd->user_width << 16) | icd->user_height, -- pcdev->base_emma + PRP_SRC_FRAME_SIZE); -- -- writel((icd->user_width << 16) | icd->user_height, -- pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); -- -- writel(prp->cfg.src_pixel, -- pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); -- -- } -- -- /* Enable interrupts */ -- writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); --} -- - static int mx2_camera_set_bus_param(struct soc_camera_device *icd) - { - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -@@ -939,31 +1052,10 @@ static int mx2_camera_set_bus_param(stru - if (bytesperline < 0) - return bytesperline; - -- if (mx27_camera_emma(pcdev)) { -+ if (cpu_is_mx27()) { - ret = mx27_camera_emma_prp_reset(pcdev); - if (ret) - return ret; -- -- if (pcdev->discard_buffer) -- dma_free_coherent(ici->v4l2_dev.dev, -- pcdev->discard_size, pcdev->discard_buffer, -- pcdev->discard_buffer_dma); -- -- /* -- * I didn't manage to properly enable/disable the prp -- * on a per frame basis during running transfers, -- * thus we allocate a buffer here and use it to -- * discard frames when no buffer is available. -- * Feel free to work on this ;) -- */ -- pcdev->discard_size = icd->user_height * bytesperline; -- pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, -- pcdev->discard_size, &pcdev->discard_buffer_dma, -- GFP_KERNEL); -- if (!pcdev->discard_buffer) -- return -ENOMEM; -- -- mx27_camera_emma_buf_init(icd, bytesperline); - } else if (cpu_is_mx25()) { - writel((bytesperline * icd->user_height) >> 2, - pcdev->base_csi + CSIRXCNT); -@@ -1052,6 +1144,123 @@ static int mx2_camera_get_formats(struct - return formats; - } - -+static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev, -+ struct v4l2_mbus_framefmt *mf_in, -+ struct v4l2_pix_format *pix_out, bool apply) -+{ -+ int num, den; -+ unsigned long m; -+ int i, dir; -+ -+ for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { -+ struct emma_prp_resize tmprsz; -+ unsigned char *s = tmprsz.s; -+ int len = 0; -+ int in, out; -+ -+ if (dir == RESIZE_DIR_H) { -+ in = mf_in->width; -+ out = pix_out->width; -+ } else { -+ in = mf_in->height; -+ out = pix_out->height; -+ } -+ -+ if (in < out) -+ return -EINVAL; -+ else if (in == out) -+ continue; -+ -+ /* Calculate ratio */ -+ m = gcd(in, out); -+ num = in / m; -+ den = out / m; -+ if (num > RESIZE_NUM_MAX) -+ return -EINVAL; -+ -+ if ((num >= 2 * den) && (den == 1) && -+ (num < 9) && (!(num & 0x01))) { -+ int sum = 0; -+ int j; -+ -+ /* Average scaling for >= 2:1 ratios */ -+ /* Support can be added for num >=9 and odd values */ -+ -+ tmprsz.algo = RESIZE_ALGO_AVERAGING; -+ len = num; -+ -+ for (i = 0; i < (len / 2); i++) -+ s[i] = 8; -+ -+ do { -+ for (i = 0; i < (len / 2); i++) { -+ s[i] = s[i] >> 1; -+ sum = 0; -+ for (j = 0; j < (len / 2); j++) -+ sum += s[j]; -+ if (sum == 4) -+ break; -+ } -+ } while (sum != 4); -+ -+ for (i = (len / 2); i < len; i++) -+ s[i] = s[len - i - 1]; -+ -+ s[len - 1] |= SZ_COEF; -+ } else { -+ /* bilinear scaling for < 2:1 ratios */ -+ int v; /* overflow counter */ -+ int coeff, nxt; /* table output */ -+ int in_pos_inc = 2 * den; -+ int out_pos = num; -+ int out_pos_inc = 2 * num; -+ int init_carry = num - den; -+ int carry = init_carry; -+ -+ tmprsz.algo = RESIZE_ALGO_BILINEAR; -+ v = den + in_pos_inc; -+ do { -+ coeff = v - out_pos; -+ out_pos += out_pos_inc; -+ carry += out_pos_inc; -+ for (nxt = 0; v < out_pos; nxt++) { -+ v += in_pos_inc; -+ carry -= in_pos_inc; -+ } -+ -+ if (len > RESIZE_NUM_MAX) -+ return -EINVAL; -+ -+ coeff = ((coeff << BC_COEF) + -+ (in_pos_inc >> 1)) / in_pos_inc; -+ -+ if (coeff >= (SZ_COEF - 1)) -+ coeff--; -+ -+ coeff |= SZ_COEF; -+ s[len] = (unsigned char)coeff; -+ len++; -+ -+ for (i = 1; i < nxt; i++) { -+ if (len >= RESIZE_NUM_MAX) -+ return -EINVAL; -+ s[len] = 0; -+ len++; -+ } -+ } while (carry != init_carry); -+ } -+ tmprsz.len = len; -+ if (dir == RESIZE_DIR_H) -+ mf_in->width = pix_out->width; -+ else -+ mf_in->height = pix_out->height; -+ -+ if (apply) -+ memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz)); -+ } -+ return 0; -+} -+ - static int mx2_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) - { -@@ -1063,6 +1272,9 @@ static int mx2_camera_set_fmt(struct soc - struct v4l2_mbus_framefmt mf; - int ret; - -+ dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", -+ __func__, pix->width, pix->height); -+ - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) { - dev_warn(icd->parent, "Format %x not found\n", -@@ -1080,6 +1292,22 @@ static int mx2_camera_set_fmt(struct soc - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - -+ /* Store width and height returned by the sensor for resizing */ -+ pcdev->s_width = mf.width; -+ pcdev->s_height = mf.height; -+ dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", -+ __func__, pcdev->s_width, pcdev->s_height); -+ -+ pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, -+ xlate->host_fmt->fourcc); -+ -+ memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); -+ if ((mf.width != pix->width || mf.height != pix->height) && -+ pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { -+ if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0) -+ dev_dbg(icd->parent, "%s: can't resize\n", __func__); -+ } -+ - if (mf.code != xlate->code) - return -EINVAL; - -@@ -1089,9 +1317,8 @@ static int mx2_camera_set_fmt(struct soc - pix->colorspace = mf.colorspace; - icd->current_fmt = xlate; - -- if (mx27_camera_emma(pcdev)) -- pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, -- xlate->host_fmt->fourcc); -+ dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", -+ __func__, pix->width, pix->height); - - return 0; - } -@@ -1104,9 +1331,14 @@ static int mx2_camera_try_fmt(struct soc - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - __u32 pixfmt = pix->pixelformat; -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct mx2_camera_dev *pcdev = ici->priv; - unsigned int width_limit; - int ret; - -+ dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", -+ __func__, pix->width, pix->height); -+ - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (pixfmt && !xlate) { - dev_warn(icd->parent, "Format %x not found\n", pixfmt); -@@ -1156,6 +1388,20 @@ static int mx2_camera_try_fmt(struct soc - if (ret < 0) - return ret; - -+ dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", -+ __func__, pcdev->s_width, pcdev->s_height); -+ -+ /* If the sensor does not support image size try PrP resizing */ -+ pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, -+ xlate->host_fmt->fourcc); -+ -+ memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); -+ if ((mf.width != pix->width || mf.height != pix->height) && -+ pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { -+ if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) -+ dev_dbg(icd->parent, "%s: can't resize\n", __func__); -+ } -+ - if (mf.field == V4L2_FIELD_ANY) - mf.field = V4L2_FIELD_NONE; - /* -@@ -1174,6 +1420,9 @@ static int mx2_camera_try_fmt(struct soc - pix->field = mf.field; - pix->colorspace = mf.colorspace; - -+ dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", -+ __func__, pix->width, pix->height); -+ - return 0; - } - -@@ -1187,136 +1436,11 @@ static int mx2_camera_querycap(struct so - return 0; - } - --static int mx2_camera_reqbufs(struct soc_camera_device *icd, -- struct v4l2_requestbuffers *p) --{ -- int i; -- -- for (i = 0; i < p->count; i++) { -- struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i], -- struct mx2_buffer, vb); -- INIT_LIST_HEAD(&buf->vb.queue); -- } -- -- return 0; --} -- --#ifdef CONFIG_MACH_MX27 --static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state) --{ -- struct videobuf_buffer *vb; -- struct mx2_buffer *buf; -- unsigned long flags; -- int ret; -- -- spin_lock_irqsave(&pcdev->lock, flags); -- -- if (!pcdev->active) { -- dev_err(pcdev->dev, "%s called with no active buffer!\n", -- __func__); -- goto out; -- } -- -- vb = &pcdev->active->vb; -- buf = container_of(vb, struct mx2_buffer, vb); -- WARN_ON(list_empty(&vb->queue)); -- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, -- vb, vb->baddr, vb->bsize); -- -- /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ -- list_del_init(&vb->queue); -- vb->state = state; -- do_gettimeofday(&vb->ts); -- vb->field_count++; -- -- wake_up(&vb->done); -- -- if (list_empty(&pcdev->capture)) { -- pcdev->active = NULL; -- goto out; -- } -- -- pcdev->active = list_entry(pcdev->capture.next, -- struct mx2_buffer, vb.queue); -- -- vb = &pcdev->active->vb; -- vb->state = VIDEOBUF_ACTIVE; -- -- ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb), -- vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ); -- -- if (ret) { -- vb->state = VIDEOBUF_ERROR; -- pcdev->active = NULL; -- wake_up(&vb->done); -- } -- --out: -- spin_unlock_irqrestore(&pcdev->lock, flags); --} -- --static void mx27_camera_dma_err_callback(int channel, void *data, int err) --{ -- struct mx2_camera_dev *pcdev = data; -- -- mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR); --} -- --static void mx27_camera_dma_callback(int channel, void *data) --{ -- struct mx2_camera_dev *pcdev = data; -- -- mx27_camera_frame_done(pcdev, VIDEOBUF_DONE); --} -- --#define DMA_REQ_CSI_RX 31 /* FIXME: Add this to a resource */ -- --static int __devinit mx27_camera_dma_init(struct platform_device *pdev, -- struct mx2_camera_dev *pcdev) --{ -- int err; -- -- pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH); -- if (pcdev->dma < 0) { -- dev_err(&pdev->dev, "%s failed to request DMA channel\n", -- __func__); -- return pcdev->dma; -- } -- -- err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback, -- mx27_camera_dma_err_callback, pcdev); -- if (err) { -- dev_err(&pdev->dev, "%s failed to set DMA callback\n", -- __func__); -- goto err_out; -- } -- -- err = imx_dma_config_channel(pcdev->dma, -- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, -- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, -- DMA_REQ_CSI_RX, 1); -- if (err) { -- dev_err(&pdev->dev, "%s failed to config DMA channel\n", -- __func__); -- goto err_out; -- } -- -- imx_dma_config_burstlen(pcdev->dma, 64); -- -- return 0; -- --err_out: -- imx_dma_free(pcdev->dma); -- -- return err; --} --#endif /* CONFIG_MACH_MX27 */ -- - static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) - { - struct soc_camera_device *icd = file->private_data; - -- return videobuf_poll_stream(file, &icd->vb_vidq, pt); -+ return vb2_poll(&icd->vb2_vidq, file, pt); - } - - static struct soc_camera_host_ops mx2_soc_camera_host_ops = { -@@ -1327,144 +1451,148 @@ static struct soc_camera_host_ops mx2_so - .set_crop = mx2_camera_set_crop, - .get_formats = mx2_camera_get_formats, - .try_fmt = mx2_camera_try_fmt, -- .init_videobuf = mx2_camera_init_videobuf, -- .reqbufs = mx2_camera_reqbufs, -+ .init_videobuf2 = mx2_camera_init_videobuf, - .poll = mx2_camera_poll, - .querycap = mx2_camera_querycap, - .set_bus_param = mx2_camera_set_bus_param, - }; - - static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, -- int bufnum, int state) -+ int bufnum, bool err) - { -- u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; -+#ifdef DEBUG - struct mx2_fmt_cfg *prp = pcdev->emma_prp; -+#endif -+ struct mx2_buf_internal *ibuf; - struct mx2_buffer *buf; -- struct videobuf_buffer *vb; -+ struct vb2_buffer *vb; - unsigned long phys; - -- if (!list_empty(&pcdev->active_bufs)) { -- buf = list_entry(pcdev->active_bufs.next, -- struct mx2_buffer, vb.queue); -+ ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal, -+ queue); - -- BUG_ON(buf->bufnum != bufnum); -+ BUG_ON(ibuf->bufnum != bufnum); -+ -+ if (ibuf->discard) { -+ /* -+ * Discard buffer must not be returned to user space. -+ * Just return it to the discard queue. -+ */ -+ list_move_tail(pcdev->active_bufs.next, &pcdev->discard); -+ } else { -+ buf = mx2_ibuf_to_buf(ibuf); - - vb = &buf->vb; - #ifdef DEBUG -- phys = videobuf_to_dma_contig(vb); -+ phys = vb2_dma_contig_plane_dma_addr(vb, 0); - if (prp->cfg.channel == 1) { - if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + - 4 * bufnum) != phys) { -- dev_err(pcdev->dev, "%p != %p\n", phys, -- readl(pcdev->base_emma + -- PRP_DEST_RGB1_PTR + -- 4 * bufnum)); -+ dev_err(pcdev->dev, "%lx != %x\n", phys, -+ readl(pcdev->base_emma + -+ PRP_DEST_RGB1_PTR + 4 * bufnum)); - } - } else { - if (readl(pcdev->base_emma + PRP_DEST_Y_PTR - - 0x14 * bufnum) != phys) { -- dev_err(pcdev->dev, "%p != %p\n", phys, -- readl(pcdev->base_emma + -- PRP_DEST_Y_PTR - -- 0x14 * bufnum)); -+ dev_err(pcdev->dev, "%lx != %x\n", phys, -+ readl(pcdev->base_emma + -+ PRP_DEST_Y_PTR - 0x14 * bufnum)); - } - } - #endif -- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, -- vb->baddr, vb->bsize); -- -- list_del(&vb->queue); -- vb->state = state; -- do_gettimeofday(&vb->ts); -- vb->field_count = pcdev->frame_count * 2; -- pcdev->frame_count++; -- -- wake_up(&vb->done); -+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, -+ vb2_plane_vaddr(vb, 0), -+ vb2_get_plane_payload(vb, 0)); -+ -+ list_del_init(&buf->internal.queue); -+ do_gettimeofday(&vb->v4l2_buf.timestamp); -+ vb->v4l2_buf.sequence = pcdev->frame_count; -+ if (err) -+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); -+ else -+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - } - -+ pcdev->frame_count++; -+ - if (list_empty(&pcdev->capture)) { -- if (prp->cfg.channel == 1) { -- writel(pcdev->discard_buffer_dma, pcdev->base_emma + -- PRP_DEST_RGB1_PTR + 4 * bufnum); -- } else { -- writel(pcdev->discard_buffer_dma, pcdev->base_emma + -- PRP_DEST_Y_PTR - -- 0x14 * bufnum); -- if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { -- writel(pcdev->discard_buffer_dma + imgsize, -- pcdev->base_emma + PRP_DEST_CB_PTR - -- 0x14 * bufnum); -- writel(pcdev->discard_buffer_dma + -- ((5 * imgsize) / 4), pcdev->base_emma + -- PRP_DEST_CR_PTR - 0x14 * bufnum); -- } -+ if (list_empty(&pcdev->discard)) { -+ dev_warn(pcdev->dev, "%s: trying to access empty discard list\n", -+ __func__); -+ return; - } -+ -+ ibuf = list_first_entry(&pcdev->discard, -+ struct mx2_buf_internal, queue); -+ ibuf->bufnum = bufnum; -+ -+ list_move_tail(pcdev->discard.next, &pcdev->active_bufs); -+ mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum); - return; - } - -- buf = list_entry(pcdev->capture.next, -- struct mx2_buffer, vb.queue); -+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer, -+ internal.queue); - -- buf->bufnum = !bufnum; -+ buf->internal.bufnum = bufnum; - - list_move_tail(pcdev->capture.next, &pcdev->active_bufs); - - vb = &buf->vb; -- vb->state = VIDEOBUF_ACTIVE; -+ buf->state = MX2_STATE_ACTIVE; - -- phys = videobuf_to_dma_contig(vb); -- if (prp->cfg.channel == 1) { -- writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); -- } else { -- writel(phys, pcdev->base_emma + -- PRP_DEST_Y_PTR - 0x14 * bufnum); -- if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { -- writel(phys + imgsize, pcdev->base_emma + -- PRP_DEST_CB_PTR - 0x14 * bufnum); -- writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + -- PRP_DEST_CR_PTR - 0x14 * bufnum); -- } -- } -+ phys = vb2_dma_contig_plane_dma_addr(vb, 0); -+ mx27_update_emma_buf(pcdev, phys, bufnum); - } - - static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) - { - struct mx2_camera_dev *pcdev = data; - unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); -- struct mx2_buffer *buf; -+ struct mx2_buf_internal *ibuf; -+ -+ spin_lock(&pcdev->lock); -+ -+ if (list_empty(&pcdev->active_bufs)) { -+ dev_warn(pcdev->dev, "%s: called while active list is empty\n", -+ __func__); -+ -+ if (!status) { -+ spin_unlock(&pcdev->lock); -+ return IRQ_NONE; -+ } -+ } - - if (status & (1 << 7)) { /* overflow */ -- u32 cntl; -- /* -- * We only disable channel 1 here since this is the only -- * enabled channel -- * -- * FIXME: the correct DMA overflow handling should be resetting -- * the buffer, returning an error frame, and continuing with -- * the next one. -- */ -- cntl = readl(pcdev->base_emma + PRP_CNTL); -+ u32 cntl = readl(pcdev->base_emma + PRP_CNTL); - writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN), - pcdev->base_emma + PRP_CNTL); - writel(cntl, pcdev->base_emma + PRP_CNTL); -- } -- if ((((status & (3 << 5)) == (3 << 5)) || -- ((status & (3 << 3)) == (3 << 3))) -- && !list_empty(&pcdev->active_bufs)) { -+ -+ ibuf = list_first_entry(&pcdev->active_bufs, -+ struct mx2_buf_internal, queue); -+ mx27_camera_frame_done_emma(pcdev, -+ ibuf->bufnum, true); -+ -+ status &= ~(1 << 7); -+ } else if (((status & (3 << 5)) == (3 << 5)) || -+ ((status & (3 << 3)) == (3 << 3))) { - /* - * Both buffers have triggered, process the one we're expecting - * to first - */ -- buf = list_entry(pcdev->active_bufs.next, -- struct mx2_buffer, vb.queue); -- mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); -- status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ -- } -- if ((status & (1 << 6)) || (status & (1 << 4))) -- mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); -- if ((status & (1 << 5)) || (status & (1 << 3))) -- mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); -+ ibuf = list_first_entry(&pcdev->active_bufs, -+ struct mx2_buf_internal, queue); -+ mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false); -+ status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */ -+ } else if ((status & (1 << 6)) || (status & (1 << 4))) { -+ mx27_camera_frame_done_emma(pcdev, 0, false); -+ } else if ((status & (1 << 5)) || (status & (1 << 3))) { -+ mx27_camera_frame_done_emma(pcdev, 1, false); -+ } - -+ spin_unlock(&pcdev->lock); - writel(status, pcdev->base_emma + PRP_INTRSTATUS); - - return IRQ_HANDLED; -@@ -1527,8 +1655,6 @@ static int __devinit mx2_camera_probe(st - struct resource *res_csi, *res_emma; - void __iomem *base_csi; - int irq_csi, irq_emma; -- irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq -- : mx27_camera_irq; - int err = 0; - - dev_dbg(&pdev->dev, "initialising\n"); -@@ -1550,22 +1676,11 @@ static int __devinit mx2_camera_probe(st - - pcdev->clk_csi = clk_get(&pdev->dev, NULL); - if (IS_ERR(pcdev->clk_csi)) { -+ dev_err(&pdev->dev, "Could not get csi clock\n"); - err = PTR_ERR(pcdev->clk_csi); - goto exit_kfree; - } - -- dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n", -- clk_get_rate(pcdev->clk_csi)); -- -- /* Initialize DMA */ --#ifdef CONFIG_MACH_MX27 -- if (cpu_is_mx27()) { -- err = mx27_camera_dma_init(pdev, pcdev); -- if (err) -- goto exit_clk_put; -- } --#endif /* CONFIG_MACH_MX27 */ -- - pcdev->res_csi = res_csi; - pcdev->pdata = pdev->dev.platform_data; - if (pcdev->pdata) { -@@ -1585,6 +1700,7 @@ static int __devinit mx2_camera_probe(st - - INIT_LIST_HEAD(&pcdev->capture); - INIT_LIST_HEAD(&pcdev->active_bufs); -+ INIT_LIST_HEAD(&pcdev->discard); - spin_lock_init(&pcdev->lock); - - /* -@@ -1606,11 +1722,13 @@ static int __devinit mx2_camera_probe(st - pcdev->base_dma = res_csi->start; - pcdev->dev = &pdev->dev; - -- err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0, -- MX2_CAM_DRV_NAME, pcdev); -- if (err) { -- dev_err(pcdev->dev, "Camera interrupt register failed \n"); -- goto exit_iounmap; -+ if (cpu_is_mx25()) { -+ err = request_irq(pcdev->irq_csi, mx25_camera_irq, 0, -+ MX2_CAM_DRV_NAME, pcdev); -+ if (err) { -+ dev_err(pcdev->dev, "Camera interrupt register failed \n"); -+ goto exit_iounmap; -+ } - } - - if (cpu_is_mx27()) { -@@ -1618,14 +1736,15 @@ static int __devinit mx2_camera_probe(st - res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); - irq_emma = platform_get_irq(pdev, 1); - -- if (res_emma && irq_emma >= 0) { -- dev_info(&pdev->dev, "Using EMMA\n"); -- pcdev->use_emma = 1; -- pcdev->res_emma = res_emma; -- pcdev->irq_emma = irq_emma; -- if (mx27_camera_emma_init(pcdev)) -- goto exit_free_irq; -+ if (!res_emma || !irq_emma) { -+ dev_err(&pdev->dev, "no EMMA resources\n"); -+ goto exit_free_irq; - } -+ -+ pcdev->res_emma = res_emma; -+ pcdev->irq_emma = irq_emma; -+ if (mx27_camera_emma_init(pcdev)) -+ goto exit_free_irq; - } - - pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, -@@ -1633,6 +1752,12 @@ static int __devinit mx2_camera_probe(st - pcdev->soc_host.priv = pcdev; - pcdev->soc_host.v4l2_dev.dev = &pdev->dev; - pcdev->soc_host.nr = pdev->id; -+ -+ pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); -+ if (IS_ERR(pcdev->alloc_ctx)) { -+ err = PTR_ERR(pcdev->alloc_ctx); -+ goto eallocctx; -+ } - err = soc_camera_host_register(&pcdev->soc_host); - if (err) - goto exit_free_emma; -@@ -1643,26 +1768,24 @@ static int __devinit mx2_camera_probe(st - return 0; - - exit_free_emma: -- if (mx27_camera_emma(pcdev)) { -+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); -+eallocctx: -+ if (cpu_is_mx27()) { - free_irq(pcdev->irq_emma, pcdev); - clk_disable(pcdev->clk_emma); - clk_put(pcdev->clk_emma); - iounmap(pcdev->base_emma); -- release_mem_region(res_emma->start, resource_size(res_emma)); -+ release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma)); - } - exit_free_irq: -- free_irq(pcdev->irq_csi, pcdev); -+ if (cpu_is_mx25()) -+ free_irq(pcdev->irq_csi, pcdev); - exit_iounmap: - iounmap(base_csi); - exit_release: - release_mem_region(res_csi->start, resource_size(res_csi)); - exit_dma_free: --#ifdef CONFIG_MACH_MX27 -- if (cpu_is_mx27()) -- imx_dma_free(pcdev->dma); --exit_clk_put: - clk_put(pcdev->clk_csi); --#endif /* CONFIG_MACH_MX27 */ - exit_kfree: - kfree(pcdev); - exit: -@@ -1677,19 +1800,18 @@ static int __devexit mx2_camera_remove(s - struct resource *res; - - clk_put(pcdev->clk_csi); --#ifdef CONFIG_MACH_MX27 -+ if (cpu_is_mx25()) -+ free_irq(pcdev->irq_csi, pcdev); - if (cpu_is_mx27()) -- imx_dma_free(pcdev->dma); --#endif /* CONFIG_MACH_MX27 */ -- free_irq(pcdev->irq_csi, pcdev); -- if (mx27_camera_emma(pcdev)) - free_irq(pcdev->irq_emma, pcdev); - - soc_camera_host_unregister(&pcdev->soc_host); - -+ vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); -+ - iounmap(pcdev->base_csi); - -- if (mx27_camera_emma(pcdev)) { -+ if (cpu_is_mx27()) { - clk_disable(pcdev->clk_emma); - clk_put(pcdev->clk_emma); - iounmap(pcdev->base_emma); -Index: linux-3.3.x86_64/drivers/media/rc/rc-core-priv.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/rc-core-priv.h -+++ linux-3.3.x86_64/drivers/media/rc/rc-core-priv.h -@@ -35,7 +35,7 @@ struct ir_raw_event_ctrl { - struct list_head list; /* to keep track of raw clients */ - struct task_struct *thread; - spinlock_t lock; -- struct kfifo kfifo; /* fifo for the pulse/space durations */ -+ struct kfifo_rec_ptr_1 kfifo; /* fifo for the pulse/space durations */ - ktime_t last_event; /* when last event occurred */ - enum raw_event_type last_type; /* last event type */ - struct rc_dev *dev; /* pointer to the parent rc_dev */ -Index: linux-3.3.x86_64/drivers/media/video/s2255drv.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/s2255drv.c -+++ linux-3.3.x86_64/drivers/media/video/s2255drv.c -@@ -134,7 +134,7 @@ - - /* usb config commands */ - #define IN_DATA_TOKEN cpu_to_le32(0x2255c0de) --#define CMD_2255 cpu_to_le32(0xc2255000) -+#define CMD_2255 0xc2255000 - #define CMD_SET_MODE cpu_to_le32((CMD_2255 | 0x10)) - #define CMD_START cpu_to_le32((CMD_2255 | 0x20)) - #define CMD_STOP cpu_to_le32((CMD_2255 | 0x30)) -@@ -852,15 +852,13 @@ static int vidioc_querycap(struct file * - static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) - { -- int index = 0; -- if (f) -- index = f->index; -+ int index = f->index; - - if (index >= ARRAY_SIZE(formats)) - return -EINVAL; -- if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || -- (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) -- return -EINVAL; -+ if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || -+ (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) -+ return -EINVAL; - dprintk(4, "name %s\n", formats[index].name); - strlcpy(f->description, formats[index].name, sizeof(f->description)); - f->pixelformat = formats[index].fourcc; -@@ -2027,7 +2025,7 @@ static int save_frame(struct s2255_dev * - pdata[1]); - offset = jj + PREFIX_SIZE; - bframe = 1; -- cc = pdword[1]; -+ cc = le32_to_cpu(pdword[1]); - if (cc >= MAX_CHANNELS) { - printk(KERN_ERR - "bad channel\n"); -@@ -2036,22 +2034,22 @@ static int save_frame(struct s2255_dev * - /* reverse it */ - dev->cc = G_chnmap[cc]; - channel = &dev->channel[dev->cc]; -- payload = pdword[3]; -+ payload = le32_to_cpu(pdword[3]); - if (payload > channel->req_image_size) { - channel->bad_payload++; - /* discard the bad frame */ - return -EINVAL; - } - channel->pkt_size = payload; -- channel->jpg_size = pdword[4]; -+ channel->jpg_size = le32_to_cpu(pdword[4]); - break; - case S2255_MARKER_RESPONSE: - - pdata += DEF_USB_BLOCK; - jj += DEF_USB_BLOCK; -- if (pdword[1] >= MAX_CHANNELS) -+ if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS) - break; -- cc = G_chnmap[pdword[1]]; -+ cc = G_chnmap[le32_to_cpu(pdword[1])]; - if (cc >= MAX_CHANNELS) - break; - channel = &dev->channel[cc]; -@@ -2074,11 +2072,11 @@ static int save_frame(struct s2255_dev * - wake_up(&dev->fw_data->wait_fw); - break; - case S2255_RESPONSE_STATUS: -- channel->vidstatus = pdword[3]; -+ channel->vidstatus = le32_to_cpu(pdword[3]); - channel->vidstatus_ready = 1; - wake_up(&channel->wait_vidstatus); - dprintk(5, "got vidstatus %x chan %d\n", -- pdword[3], cc); -+ le32_to_cpu(pdword[3]), cc); - break; - default: - printk(KERN_INFO "s2255 unknown resp\n"); -@@ -2605,10 +2603,11 @@ static int s2255_probe(struct usb_interf - __le32 *pRel; - pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; - printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel); -- dev->dsp_fw_ver = *pRel; -- if (*pRel < S2255_CUR_DSP_FWVER) -+ dev->dsp_fw_ver = le32_to_cpu(*pRel); -+ if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) - printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); -- if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER) -+ if (dev->pid == 0x2257 && -+ dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - printk(KERN_WARNING "s2255: 2257 requires firmware %d" - " or above.\n", S2255_MIN_DSP_COLORFILTER); - } -Index: linux-3.3.x86_64/drivers/media/common/tuners/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/common/tuners/Makefile -+++ linux-3.3.x86_64/drivers/media/common/tuners/Makefile -@@ -28,6 +28,8 @@ obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc - obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o - obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o - obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o -+obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o -+obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o - --ccflags-y += -Idrivers/media/dvb/dvb-core --ccflags-y += -Idrivers/media/dvb/frontends -+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core -+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends -Index: linux-3.3.x86_64/drivers/media/video/saa7134/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7134/Makefile -+++ linux-3.3.x86_64/drivers/media/video/saa7134/Makefile -@@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7 - - obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o - --ccflags-y += -Idrivers/media/video --ccflags-y += -Idrivers/media/common/tuners --ccflags-y += -Idrivers/media/dvb/dvb-core --ccflags-y += -Idrivers/media/dvb/frontends -+ccflags-y += -I$(srctree)/drivers/media/video -+ccflags-y += -I$(srctree)/drivers/media/common/tuners -+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core -+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends -Index: linux-3.3.x86_64/drivers/media/video/saa7164/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7164/Makefile -+++ linux-3.3.x86_64/drivers/media/video/saa7164/Makefile -@@ -4,9 +4,9 @@ saa7164-objs := saa7164-cards.o saa7164- - - obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o - --ccflags-y += -Idrivers/media/video --ccflags-y += -Idrivers/media/common/tuners --ccflags-y += -Idrivers/media/dvb/dvb-core --ccflags-y += -Idrivers/media/dvb/frontends -+ccflags-y += -I$(srctree)/drivers/media/video -+ccflags-y += -I$(srctree)/drivers/media/common/tuners -+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core -+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends - - ccflags-y += $(extra-cflags-y) $(extra-cflags-m) -Index: linux-3.3.x86_64/drivers/media/video/ivtv/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/Makefile -+++ linux-3.3.x86_64/drivers/media/video/ivtv/Makefile -@@ -7,8 +7,8 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o - obj-$(CONFIG_VIDEO_IVTV) += ivtv.o - obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o - --ccflags-y += -Idrivers/media/video --ccflags-y += -Idrivers/media/common/tuners --ccflags-y += -Idrivers/media/dvb/dvb-core --ccflags-y += -Idrivers/media/dvb/frontends -+ccflags-y += -I$(srctree)/drivers/media/video -+ccflags-y += -I$(srctree)/drivers/media/common/tuners -+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core -+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends - -Index: linux-3.3.x86_64/drivers/media/video/gspca/gl860/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/gspca/gl860/Makefile -+++ linux-3.3.x86_64/drivers/media/video/gspca/gl860/Makefile -@@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \ - gl860-ov9655.o \ - gl860-mi2020.o - --ccflags-y += -Idrivers/media/video/gspca -+ccflags-y += -I$(srctree)/drivers/media/video/gspca - -Index: linux-3.3.x86_64/drivers/media/video/gspca/m5602/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/gspca/m5602/Makefile -+++ linux-3.3.x86_64/drivers/media/video/gspca/m5602/Makefile -@@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \ - m5602_s5k83a.o \ - m5602_s5k4aa.o - --ccflags-y += -Idrivers/media/video/gspca -+ccflags-y += -I$(srctree)/drivers/media/video/gspca -Index: linux-3.3.x86_64/drivers/media/video/gspca/stv06xx/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/gspca/stv06xx/Makefile -+++ linux-3.3.x86_64/drivers/media/video/gspca/stv06xx/Makefile -@@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \ - stv06xx_pb0100.o \ - stv06xx_st6422.o - --ccflags-y += -Idrivers/media/video/gspca -+ccflags-y += -I$(srctree)/drivers/media/video/gspca - -Index: linux-3.3.x86_64/Documentation/dvb/cards.txt -=================================================================== ---- linux-3.3.x86_64.orig/Documentation/dvb/cards.txt -+++ linux-3.3.x86_64/Documentation/dvb/cards.txt -@@ -119,4 +119,5 @@ o Cards based on the Phillips saa7134 PC - - Compro Videomate DVB-T300 - - Compro Videomate DVB-T200 - - AVerMedia AVerTVHD MCE A180 -+ - KWorld PC150-U ATSC Hybrid - -Index: linux-3.3.x86_64/drivers/media/rc/keymaps/rc-kworld-pc150u.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/rc/keymaps/rc-kworld-pc150u.c -@@ -0,0 +1,102 @@ -+/* kworld-pc150u.c - Keytable for kworld_pc150u Remote Controller -+ * -+ * keymap imported from ir-keymaps.c -+ * -+ * Copyright (c) 2010 by Kyle Strickland -+ * (based on kworld-plus-tv-analog.c by -+ * Mauro Carvalho Chehab ) -+ * -+ * 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. -+ */ -+ -+#include -+#include -+ -+/* Kworld PC150-U -+ Kyle Strickland -+ */ -+ -+static struct rc_map_table kworld_pc150u[] = { -+ { 0x0c, KEY_MEDIA }, /* Kworld key */ -+ { 0x16, KEY_EJECTCLOSECD }, /* -> ) */ -+ { 0x1d, KEY_POWER2 }, -+ -+ { 0x00, KEY_1 }, -+ { 0x01, KEY_2 }, -+ { 0x02, KEY_3 }, -+ { 0x03, KEY_4 }, -+ { 0x04, KEY_5 }, -+ { 0x05, KEY_6 }, -+ { 0x06, KEY_7 }, -+ { 0x07, KEY_8 }, -+ { 0x08, KEY_9 }, -+ { 0x0a, KEY_0 }, -+ -+ { 0x09, KEY_AGAIN }, -+ { 0x14, KEY_MUTE }, -+ -+ { 0x1e, KEY_LAST }, -+ { 0x17, KEY_ZOOM }, -+ { 0x1f, KEY_HOMEPAGE }, -+ { 0x0e, KEY_ESC }, -+ -+ { 0x20, KEY_UP }, -+ { 0x21, KEY_DOWN }, -+ { 0x42, KEY_LEFT }, -+ { 0x43, KEY_RIGHT }, -+ { 0x0b, KEY_ENTER }, -+ -+ { 0x10, KEY_CHANNELUP }, -+ { 0x11, KEY_CHANNELDOWN }, -+ -+ { 0x13, KEY_VOLUMEUP }, -+ { 0x12, KEY_VOLUMEDOWN }, -+ -+ { 0x19, KEY_TIME}, /* Timeshift */ -+ { 0x1a, KEY_STOP}, -+ { 0x1b, KEY_RECORD}, -+ { 0x4b, KEY_EMAIL}, -+ -+ { 0x40, KEY_REWIND}, -+ { 0x44, KEY_PLAYPAUSE}, -+ { 0x41, KEY_FORWARD}, -+ { 0x22, KEY_TEXT}, -+ -+ { 0x15, KEY_AUDIO}, /* ((*)) */ -+ { 0x0f, KEY_MODE}, /* display ratio */ -+ { 0x1c, KEY_SYSRQ}, /* snapshot */ -+ { 0x4a, KEY_SLEEP}, /* sleep timer */ -+ -+ { 0x48, KEY_SOUND}, /* switch theater mode */ -+ { 0x49, KEY_BLUE}, /* A */ -+ { 0x18, KEY_RED}, /* B */ -+ { 0x23, KEY_GREEN}, /* C */ -+}; -+ -+static struct rc_map_list kworld_pc150u_map = { -+ .map = { -+ .scan = kworld_pc150u, -+ .size = ARRAY_SIZE(kworld_pc150u), -+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ -+ .name = RC_MAP_KWORLD_PC150U, -+ } -+}; -+ -+static int __init init_rc_map_kworld_pc150u(void) -+{ -+ return rc_map_register(&kworld_pc150u_map); -+} -+ -+static void __exit exit_rc_map_kworld_pc150u(void) -+{ -+ rc_map_unregister(&kworld_pc150u_map); -+} -+ -+module_init(init_rc_map_kworld_pc150u) -+module_exit(exit_rc_map_kworld_pc150u) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Kyle Strickland "); -Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-cards.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134-cards.c -+++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-cards.c -@@ -33,6 +33,7 @@ - #include "tea5767.h" - #include "tda18271.h" - #include "xc5000.h" -+#include "s5h1411.h" - - /* commly used strings */ - static char name_mute[] = "mute"; -@@ -5712,6 +5713,36 @@ struct saa7134_board saa7134_boards[] = - .amux = LINE1, - } }, - }, -+ [SAA7134_BOARD_KWORLD_PC150U] = { -+ .name = "Kworld PC150-U", -+ .audio_clock = 0x00187de7, -+ .tuner_type = TUNER_PHILIPS_TDA8290, -+ .radio_type = UNSET, -+ .tuner_addr = ADDR_UNSET, -+ .radio_addr = ADDR_UNSET, -+ .mpeg = SAA7134_MPEG_DVB, -+ .gpiomask = 1 << 21, -+ .ts_type = SAA7134_MPEG_TS_PARALLEL, -+ .inputs = { { -+ .name = name_tv, -+ .vmux = 1, -+ .amux = TV, -+ .tv = 1, -+ }, { -+ .name = name_comp, -+ .vmux = 3, -+ .amux = LINE1, -+ }, { -+ .name = name_svideo, -+ .vmux = 8, -+ .amux = LINE2, -+ } }, -+ .radio = { -+ .name = name_radio, -+ .amux = TV, -+ .gpio = 0x0000000, -+ }, -+ }, - - }; - -@@ -6306,6 +6337,12 @@ struct pci_device_id saa7134_pci_tbl[] = - .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, -+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ -+ .subvendor = 0x17de, -+ .subdevice = 0xa134, -+ .driver_data = SAA7134_BOARD_KWORLD_PC150U, -+ }, { -+ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x7360, -@@ -7134,6 +7171,23 @@ static inline int saa7134_kworld_sbtvd_t - return 0; - } - -+static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev, -+ enum tda18271_mode mode) -+{ -+ switch (mode) { -+ case TDA18271_ANALOG: -+ saa7134_set_gpio(dev, 18, 0); -+ break; -+ case TDA18271_DIGITAL: -+ saa7134_set_gpio(dev, 18, 1); -+ msleep(30); -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ - static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, - int command, int arg) - { -@@ -7150,6 +7204,9 @@ static int saa7134_tda8290_18271_callbac - case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: - ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg); - break; -+ case SAA7134_BOARD_KWORLD_PC150U: -+ ret = saa7134_kworld_pc150u_toggle_agc(dev, arg); -+ break; - default: - break; - } -@@ -7171,6 +7228,7 @@ static int saa7134_tda8290_callback(stru - case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_AVERMEDIA_M733A: - case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: -+ case SAA7134_BOARD_KWORLD_PC150U: - case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: - /* tda8290 + tda18271 */ - ret = saa7134_tda8290_18271_callback(dev, command, arg); -@@ -7452,6 +7510,7 @@ int saa7134_board_init1(struct saa7134_d - case SAA7134_BOARD_BEHOLD_X7: - case SAA7134_BOARD_BEHOLD_H7: - case SAA7134_BOARD_BEHOLD_A7: -+ case SAA7134_BOARD_KWORLD_PC150U: - dev->has_remote = SAA7134_REMOTE_I2C; - break; - case SAA7134_BOARD_AVERMEDIA_A169_B: -Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-dvb.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134-dvb.c -+++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-dvb.c -@@ -61,6 +61,7 @@ - #include "zl10036.h" - #include "zl10039.h" - #include "mt312.h" -+#include "s5h1411.h" - - MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); - MODULE_LICENSE("GPL"); -@@ -1158,6 +1159,33 @@ static struct tda18271_config prohdtv_pr - .output_opt = TDA18271_OUTPUT_LT_OFF, - }; - -+static struct tda18271_std_map kworld_tda18271_std_map = { -+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3, -+ .if_lvl = 6, .rfagc_top = 0x37 }, -+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, -+ .if_lvl = 6, .rfagc_top = 0x37 }, -+}; -+ -+static struct tda18271_config kworld_pc150u_tda18271_config = { -+ .std_map = &kworld_tda18271_std_map, -+ .gate = TDA18271_GATE_ANALOG, -+ .output_opt = TDA18271_OUTPUT_LT_OFF, -+ .config = 3, /* Use tuner callback for AGC */ -+ .rf_cal_on_startup = 1 -+}; -+ -+static struct s5h1411_config kworld_s5h1411_config = { -+ .output_mode = S5H1411_PARALLEL_OUTPUT, -+ .gpio = S5H1411_GPIO_OFF, -+ .qam_if = S5H1411_IF_4000, -+ .vsb_if = S5H1411_IF_3250, -+ .inversion = S5H1411_INVERSION_ON, -+ .status_mode = S5H1411_DEMODLOCKING, -+ .mpeg_timing = -+ S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -+}; -+ -+ - /* ================================================================== - * Core code - */ -@@ -1438,6 +1466,22 @@ static int dvb_init(struct saa7134_dev * - &dev->i2c_adap, 0x61, - TUNER_PHILIPS_TUV1236D); - break; -+ case SAA7134_BOARD_KWORLD_PC150U: -+ saa7134_set_gpio(dev, 18, 1); /* Switch to digital mode */ -+ saa7134_tuner_callback(dev, 0, -+ TDA18271_CALLBACK_CMD_AGC_ENABLE, 1); -+ fe0->dvb.frontend = dvb_attach(s5h1411_attach, -+ &kworld_s5h1411_config, -+ &dev->i2c_adap); -+ if (fe0->dvb.frontend != NULL) { -+ dvb_attach(tda829x_attach, fe0->dvb.frontend, -+ &dev->i2c_adap, 0x4b, -+ &tda829x_no_probe); -+ dvb_attach(tda18271_attach, fe0->dvb.frontend, -+ 0x60, &dev->i2c_adap, -+ &kworld_pc150u_tda18271_config); -+ } -+ break; - case SAA7134_BOARD_FLYDVBS_LR300: - fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, - &dev->i2c_adap); -Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-i2c.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134-i2c.c -+++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-i2c.c -@@ -254,7 +254,9 @@ static int saa7134_i2c_xfer(struct i2c_a - addr = msgs[i].addr << 1; - if (msgs[i].flags & I2C_M_RD) - addr |= 1; -- if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) { -+ if (i > 0 && msgs[i].flags & -+ I2C_M_RD && msgs[i].addr != 0x40 && -+ msgs[i].addr != 0x19) { - /* workaround for a saa7134 i2c bug - * needed to talk to the mt352 demux - * thanks to pinnacle for the hint */ -@@ -279,6 +281,16 @@ static int saa7134_i2c_xfer(struct i2c_a - d1printk("%02x", rc); - msgs[i].buf[byte] = rc; - } -+ /* discard mysterious extra byte when reading -+ from Samsung S5H1411. i2c bus gets error -+ if we do not. */ -+ if (0x19 == msgs[i].addr) { -+ d1printk(" ?"); -+ rc = i2c_recv_byte(dev); -+ if (rc < 0) -+ goto err; -+ d1printk("%02x", rc); -+ } - } else { - /* write bytes */ - d2printk("write bytes\n"); -Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-input.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134-input.c -+++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134-input.c -@@ -210,6 +210,54 @@ static int get_key_msi_tvanywhere_plus(s - return 1; - } - -+/* copied and modified from get_key_msi_tvanywhere_plus() */ -+static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key, -+ u32 *ir_raw) -+{ -+ unsigned char b; -+ unsigned int gpio; -+ -+ /* is needed to access GPIO. Used by the saa_readl macro. */ -+ struct saa7134_dev *dev = ir->c->adapter->algo_data; -+ if (dev == NULL) { -+ i2cdprintk("get_key_kworld_pc150u: " -+ "ir->c->adapter->algo_data is NULL!\n"); -+ return -EIO; -+ } -+ -+ /* rising SAA7134_GPIO_GPRESCAN reads the status */ -+ -+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); -+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); -+ -+ gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); -+ -+ /* GPIO&0x100 is pulsed low when a button is pressed. Don't do -+ I2C receive if gpio&0x100 is not low. */ -+ -+ if (gpio & 0x100) -+ return 0; /* No button press */ -+ -+ /* GPIO says there is a button press. Get it. */ -+ -+ if (1 != i2c_master_recv(ir->c, &b, 1)) { -+ i2cdprintk("read error\n"); -+ return -EIO; -+ } -+ -+ /* No button press */ -+ -+ if (b == 0xff) -+ return 0; -+ -+ /* Button pressed */ -+ -+ dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b); -+ *ir_key = b; -+ *ir_raw = b; -+ return 1; -+} -+ - static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) - { - unsigned char b; -@@ -894,6 +942,21 @@ void saa7134_probe_i2c_ir(struct saa7134 - info.addr = 0x30; - /* MSI TV@nywhere Plus controller doesn't seem to - respond to probes unless we read something from -+ an existing device. Weird... -+ REVISIT: might no longer be needed */ -+ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); -+ dprintk("probe 0x%02x @ %s: %s\n", -+ msg_msi.addr, dev->i2c_adap.name, -+ (1 == rc) ? "yes" : "no"); -+ break; -+ case SAA7134_BOARD_KWORLD_PC150U: -+ /* copied and modified from MSI TV@nywhere Plus */ -+ dev->init_data.name = "Kworld PC150-U"; -+ dev->init_data.get_key = get_key_kworld_pc150u; -+ dev->init_data.ir_codes = RC_MAP_KWORLD_PC150U; -+ info.addr = 0x30; -+ /* MSI TV@nywhere Plus controller doesn't seem to -+ respond to probes unless we read something from - an existing device. Weird... - REVISIT: might no longer be needed */ - rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); -Index: linux-3.3.x86_64/drivers/media/video/saa7134/saa7134.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/saa7134/saa7134.h -+++ linux-3.3.x86_64/drivers/media/video/saa7134/saa7134.h -@@ -126,8 +126,8 @@ struct saa7134_card_ir { - unsigned users; - - u32 polling; -- u32 last_gpio; -- u32 mask_keycode, mask_keydown, mask_keyup; -+ u32 last_gpio; -+ u32 mask_keycode, mask_keydown, mask_keyup; - - bool running; - bool active; -@@ -331,6 +331,7 @@ struct saa7134_card_ir { - #define SAA7134_BOARD_BEHOLD_501 186 - #define SAA7134_BOARD_BEHOLD_503FM 187 - #define SAA7134_BOARD_SENSORAY811_911 188 -+#define SAA7134_BOARD_KWORLD_PC150U 189 - - #define SAA7134_MAXBOARDS 32 - #define SAA7134_INPUT_MAX 8 -Index: linux-3.3.x86_64/drivers/media/video/cx18/cx18-driver.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx18/cx18-driver.c -+++ linux-3.3.x86_64/drivers/media/video/cx18/cx18-driver.c -@@ -38,7 +38,7 @@ - #include "cx18-ioctl.h" - #include "cx18-controls.h" - #include "tuner-xc2028.h" -- -+#include - #include - - /* If you have already X v4l cards, then set this to X. This way -@@ -75,7 +75,7 @@ static int radio[CX18_MAX_CARDS] = { -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; - static unsigned cardtype_c = 1; - static unsigned tuner_c = 1; --static bool radio_c = 1; -+static unsigned radio_c = 1; - static char pal[] = "--"; - static char secam[] = "--"; - static char ntsc[] = "-"; -@@ -110,7 +110,7 @@ static int retry_mmio = 1; - int cx18_debug; - - module_param_array(tuner, int, &tuner_c, 0644); --module_param_array(radio, bool, &radio_c, 0644); -+module_param_array(radio, int, &radio_c, 0644); - module_param_array(cardtype, int, &cardtype_c, 0644); - module_param_string(pal, pal, sizeof(pal), 0644); - module_param_string(secam, secam, sizeof(secam), 0644); -@@ -812,7 +812,7 @@ static int cx18_setup_pci(struct cx18 *c - CX18_ERR("Can't enable device %d!\n", cx->instance); - return -EIO; - } -- if (pci_set_dma_mask(pci_dev, 0xffffffff)) { -+ if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) { - CX18_ERR("No suitable DMA available, card %d\n", cx->instance); - return -EIO; - } -Index: linux-3.3.x86_64/drivers/media/rc/Kconfig -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/Kconfig -+++ linux-3.3.x86_64/drivers/media/rc/Kconfig -@@ -266,4 +266,13 @@ config RC_LOOPBACK - To compile this driver as a module, choose M here: the module will - be called rc_loopback. - -+config IR_GPIO_CIR -+ tristate "GPIO IR remote control" -+ depends on RC_CORE -+ ---help--- -+ Say Y if you want to use GPIO based IR Receiver. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called gpio-ir-recv. -+ - endif #RC_CORE -Index: linux-3.3.x86_64/drivers/media/rc/Makefile -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/Makefile -+++ linux-3.3.x86_64/drivers/media/rc/Makefile -@@ -26,3 +26,4 @@ obj-$(CONFIG_IR_REDRAT3) += redrat3.o - obj-$(CONFIG_IR_STREAMZAP) += streamzap.o - obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o - obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o -+obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o -Index: linux-3.3.x86_64/drivers/media/rc/gpio-ir-recv.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/rc/gpio-ir-recv.c -@@ -0,0 +1,205 @@ -+/* Copyright (c) 2012, Code Aurora Forum. 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 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define GPIO_IR_DRIVER_NAME "gpio-rc-recv" -+#define GPIO_IR_DEVICE_NAME "gpio_ir_recv" -+ -+struct gpio_rc_dev { -+ struct rc_dev *rcdev; -+ int gpio_nr; -+ bool active_low; -+}; -+ -+static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) -+{ -+ struct gpio_rc_dev *gpio_dev = dev_id; -+ int gval; -+ int rc = 0; -+ enum raw_event_type type = IR_SPACE; -+ -+ gval = gpio_get_value_cansleep(gpio_dev->gpio_nr); -+ -+ if (gval < 0) -+ goto err_get_value; -+ -+ if (gpio_dev->active_low) -+ gval = !gval; -+ -+ if (gval == 1) -+ type = IR_PULSE; -+ -+ rc = ir_raw_event_store_edge(gpio_dev->rcdev, type); -+ if (rc < 0) -+ goto err_get_value; -+ -+ ir_raw_event_handle(gpio_dev->rcdev); -+ -+err_get_value: -+ return IRQ_HANDLED; -+} -+ -+static int __devinit gpio_ir_recv_probe(struct platform_device *pdev) -+{ -+ struct gpio_rc_dev *gpio_dev; -+ struct rc_dev *rcdev; -+ const struct gpio_ir_recv_platform_data *pdata = -+ pdev->dev.platform_data; -+ int rc; -+ -+ if (!pdata) -+ return -EINVAL; -+ -+ if (pdata->gpio_nr < 0) -+ return -EINVAL; -+ -+ gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL); -+ if (!gpio_dev) -+ return -ENOMEM; -+ -+ rcdev = rc_allocate_device(); -+ if (!rcdev) { -+ rc = -ENOMEM; -+ goto err_allocate_device; -+ } -+ -+ rcdev->driver_type = RC_DRIVER_IR_RAW; -+ rcdev->allowed_protos = RC_TYPE_ALL; -+ rcdev->input_name = GPIO_IR_DEVICE_NAME; -+ rcdev->input_id.bustype = BUS_HOST; -+ rcdev->driver_name = GPIO_IR_DRIVER_NAME; -+ rcdev->map_name = RC_MAP_EMPTY; -+ -+ gpio_dev->rcdev = rcdev; -+ gpio_dev->gpio_nr = pdata->gpio_nr; -+ gpio_dev->active_low = pdata->active_low; -+ -+ rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv"); -+ if (rc < 0) -+ goto err_gpio_request; -+ rc = gpio_direction_input(pdata->gpio_nr); -+ if (rc < 0) -+ goto err_gpio_direction_input; -+ -+ rc = rc_register_device(rcdev); -+ if (rc < 0) { -+ dev_err(&pdev->dev, "failed to register rc device\n"); -+ goto err_register_rc_device; -+ } -+ -+ platform_set_drvdata(pdev, gpio_dev); -+ -+ rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr), -+ gpio_ir_recv_irq, -+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, -+ "gpio-ir-recv-irq", gpio_dev); -+ if (rc < 0) -+ goto err_request_irq; -+ -+ return 0; -+ -+err_request_irq: -+ platform_set_drvdata(pdev, NULL); -+ rc_unregister_device(rcdev); -+err_register_rc_device: -+err_gpio_direction_input: -+ gpio_free(pdata->gpio_nr); -+err_gpio_request: -+ rc_free_device(rcdev); -+ rcdev = NULL; -+err_allocate_device: -+ kfree(gpio_dev); -+ return rc; -+} -+ -+static int __devexit gpio_ir_recv_remove(struct platform_device *pdev) -+{ -+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); -+ -+ free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); -+ platform_set_drvdata(pdev, NULL); -+ rc_unregister_device(gpio_dev->rcdev); -+ gpio_free(gpio_dev->gpio_nr); -+ rc_free_device(gpio_dev->rcdev); -+ kfree(gpio_dev); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int gpio_ir_recv_suspend(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); -+ -+ if (device_may_wakeup(dev)) -+ enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); -+ else -+ disable_irq(gpio_to_irq(gpio_dev->gpio_nr)); -+ -+ return 0; -+} -+ -+static int gpio_ir_recv_resume(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); -+ -+ if (device_may_wakeup(dev)) -+ disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); -+ else -+ enable_irq(gpio_to_irq(gpio_dev->gpio_nr)); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops gpio_ir_recv_pm_ops = { -+ .suspend = gpio_ir_recv_suspend, -+ .resume = gpio_ir_recv_resume, -+}; -+#endif -+ -+static struct platform_driver gpio_ir_recv_driver = { -+ .probe = gpio_ir_recv_probe, -+ .remove = __devexit_p(gpio_ir_recv_remove), -+ .driver = { -+ .name = GPIO_IR_DRIVER_NAME, -+ .owner = THIS_MODULE, -+#ifdef CONFIG_PM -+ .pm = &gpio_ir_recv_pm_ops, -+#endif -+ }, -+}; -+ -+static int __init gpio_ir_recv_init(void) -+{ -+ return platform_driver_register(&gpio_ir_recv_driver); -+} -+module_init(gpio_ir_recv_init); -+ -+static void __exit gpio_ir_recv_exit(void) -+{ -+ platform_driver_unregister(&gpio_ir_recv_driver); -+} -+module_exit(gpio_ir_recv_exit); -+ -+MODULE_DESCRIPTION("GPIO IR Receiver driver"); -+MODULE_LICENSE("GPL v2"); -Index: linux-3.3.x86_64/include/media/gpio-ir-recv.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/include/media/gpio-ir-recv.h -@@ -0,0 +1,22 @@ -+/* Copyright (c) 2012, Code Aurora Forum. 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 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * 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. -+ */ -+ -+#ifndef __GPIO_IR_RECV_H__ -+#define __GPIO_IR_RECV_H__ -+ -+struct gpio_ir_recv_platform_data { -+ int gpio_nr; -+ bool active_low; -+}; -+ -+#endif /* __GPIO_IR_RECV_H__ */ -+ -Index: linux-3.3.x86_64/drivers/media/rc/ir-sony-decoder.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/ir-sony-decoder.c -+++ linux-3.3.x86_64/drivers/media/rc/ir-sony-decoder.c -@@ -130,7 +130,7 @@ static int ir_sony_decode(struct rc_dev - case 15: - device = bitrev8((data->bits >> 0) & 0xFF); - subdevice = 0; -- function = bitrev8((data->bits >> 7) & 0xFD); -+ function = bitrev8((data->bits >> 7) & 0xFE); - break; - case 20: - device = bitrev8((data->bits >> 5) & 0xF8); -Index: linux-3.3.x86_64/drivers/media/video/cx25821/cx25821-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx25821/cx25821-core.c -+++ linux-3.3.x86_64/drivers/media/video/cx25821/cx25821-core.c -@@ -1474,8 +1474,13 @@ static DEFINE_PCI_DEVICE_TABLE(cx25821_p - .device = 0x8210, - .subvendor = 0x14f1, - .subdevice = 0x0920, -- }, -- { -+ }, { -+ /* CX25821 No Brand */ -+ .vendor = 0x14f1, -+ .device = 0x8210, -+ .subvendor = 0x0000, -+ .subdevice = 0x0000, -+ }, { - /* --- end of list --- */ - } - }; -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/dib0090.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/dib0090.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/dib0090.c -@@ -519,7 +519,7 @@ static int dib0090_fw_identify(struct dv - return 0; - - identification_error: -- return -EIO;; -+ return -EIO; - } - - static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/stb0899_drv.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/stb0899_drv.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/stb0899_drv.c -@@ -67,7 +67,7 @@ static const struct stb0899_tab stb0899_ - * Crude linear extrapolation below -84.8dBm and above -8.0dBm. - */ - static const struct stb0899_tab stb0899_dvbsrf_tab[] = { -- { -950, -128 }, -+ { -750, -128 }, - { -748, -94 }, - { -745, -92 }, - { -735, -90 }, -@@ -131,7 +131,7 @@ static const struct stb0899_tab stb0899_ - { -730, 13645 }, - { -750, 13909 }, - { -766, 14153 }, -- { -999, 16383 } -+ { -950, 16383 } - }; - - /* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/ -@@ -964,6 +964,7 @@ static int stb0899_read_signal_strength( - - int val; - u32 reg; -+ *strength = 0; - switch (state->delsys) { - case SYS_DVBS: - case SYS_DSS: -@@ -983,11 +984,11 @@ static int stb0899_read_signal_strength( - break; - case SYS_DVBS2: - if (internal->lock) { -- reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN); -+ reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN); - val = STB0899_GETFIELD(IF_AGC_GAIN, reg); - - *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); -- *strength += 750; -+ *strength += 950; - dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", - val & 0x3fff, *strength); - } -@@ -1009,6 +1010,7 @@ static int stb0899_read_snr(struct dvb_f - u8 buf[2]; - u32 reg; - -+ *snr = 0; - reg = stb0899_read_reg(state, STB0899_VSTATUS); - switch (state->delsys) { - case SYS_DVBS: -@@ -1071,7 +1073,7 @@ static int stb0899_read_status(struct dv - reg = stb0899_read_reg(state, STB0899_VSTATUS); - if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { - dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK"); -- *status |= FE_HAS_CARRIER | FE_HAS_LOCK; -+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK; - - reg = stb0899_read_reg(state, STB0899_PLPARM); - if (STB0899_GETFIELD(VITCURPUN, reg)) { -Index: linux-3.3.x86_64/include/sound/tea575x-tuner.h -=================================================================== ---- linux-3.3.x86_64.orig/include/sound/tea575x-tuner.h -+++ linux-3.3.x86_64/include/sound/tea575x-tuner.h -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - - #define TEA575X_FMIF 10700 - -@@ -42,13 +43,16 @@ struct snd_tea575x_ops { - }; - - struct snd_tea575x { -+ struct v4l2_device *v4l2_dev; - struct video_device vd; /* video device */ -+ int radio_nr; /* radio_nr */ - bool tea5759; /* 5759 chip is present */ -+ bool cannot_read_data; /* Device cannot read the data pin */ - bool mute; /* Device is muted? */ - bool stereo; /* receiving stereo */ - bool tuned; /* tuned to a station */ - unsigned int val; /* hw value */ -- unsigned long freq; /* frequency */ -+ u32 freq; /* frequency */ - struct mutex mutex; - struct snd_tea575x_ops *ops; - void *private_data; -Index: linux-3.3.x86_64/sound/i2c/other/tea575x-tuner.c -=================================================================== ---- linux-3.3.x86_64.orig/sound/i2c/other/tea575x-tuner.c -+++ linux-3.3.x86_64/sound/i2c/other/tea575x-tuner.c -@@ -25,21 +25,20 @@ - #include - #include - #include --#include -+#include -+#include - #include -+#include - #include -+#include - #include - - MODULE_AUTHOR("Jaroslav Kysela "); - MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); - MODULE_LICENSE("GPL"); - --static int radio_nr = -1; --module_param(radio_nr, int, 0); -- --#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) --#define FREQ_LO (50UL * 16000) --#define FREQ_HI (150UL * 16000) -+#define FREQ_LO (76U * 16000) -+#define FREQ_HI (108U * 16000) - - /* - * definitions -@@ -121,28 +120,10 @@ static unsigned int snd_tea575x_read(str - return data; - } - --static void snd_tea575x_get_freq(struct snd_tea575x *tea) --{ -- unsigned long freq; -- -- freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK; -- /* freq *= 12.5 */ -- freq *= 125; -- freq /= 10; -- /* crystal fixup */ -- if (tea->tea5759) -- freq += TEA575X_FMIF; -- else -- freq -= TEA575X_FMIF; -- -- tea->freq = freq * 16; /* from kHz */ --} -- - static void snd_tea575x_set_freq(struct snd_tea575x *tea) - { -- unsigned long freq; -+ u32 freq = tea->freq; - -- freq = clamp(tea->freq, FREQ_LO, FREQ_HI); - freq /= 16; /* to kHz */ - /* crystal fixup */ - if (tea->tea5759) -@@ -167,12 +148,14 @@ static int vidioc_querycap(struct file * - { - struct snd_tea575x *tea = video_drvdata(file); - -- strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver)); -+ strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver)); - strlcpy(v->card, tea->card, sizeof(v->card)); - strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); - strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); -- v->version = RADIO_VERSION; -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -+ if (!tea->cannot_read_data) -+ v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; -+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; - } - -@@ -191,18 +174,24 @@ static int vidioc_g_tuner(struct file *f - v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - v->rangelow = FREQ_LO; - v->rangehigh = FREQ_HI; -- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; -- v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; -+ v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; -+ v->audmode = (tea->val & TEA575X_BIT_MONO) ? -+ V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO; - v->signal = tea->tuned ? 0xffff : 0; -- - return 0; - } - - static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) - { -- if (v->index > 0) -+ struct snd_tea575x *tea = video_drvdata(file); -+ -+ if (v->index) - return -EINVAL; -+ tea->val &= ~TEA575X_BIT_MONO; -+ if (v->audmode == V4L2_TUNER_MODE_MONO) -+ tea->val |= TEA575X_BIT_MONO; -+ snd_tea575x_write(tea, tea->val); - return 0; - } - -@@ -214,7 +203,6 @@ static int vidioc_g_frequency(struct fil - if (f->tuner != 0) - return -EINVAL; - f->type = V4L2_TUNER_RADIO; -- snd_tea575x_get_freq(tea); - f->frequency = tea->freq; - return 0; - } -@@ -227,32 +215,47 @@ static int vidioc_s_frequency(struct fil - if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) - return -EINVAL; - -- if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) -- return -EINVAL; -- -- tea->freq = f->frequency; -- -+ tea->val &= ~TEA575X_BIT_SEARCH; -+ tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI); - snd_tea575x_set_freq(tea); -- - return 0; - } - --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) -+static int vidioc_s_hw_freq_seek(struct file *file, void *fh, -+ struct v4l2_hw_freq_seek *a) - { -- if (a->index > 1) -- return -EINVAL; -- -- strcpy(a->name, "Radio"); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; --} -+ struct snd_tea575x *tea = video_drvdata(file); - --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- if (a->index != 0) -+ if (tea->cannot_read_data) -+ return -ENOTTY; -+ if (a->tuner || a->wrap_around) - return -EINVAL; -+ tea->val |= TEA575X_BIT_SEARCH; -+ tea->val &= ~TEA575X_BIT_UPDOWN; -+ if (a->seek_upward) -+ tea->val |= TEA575X_BIT_UPDOWN; -+ snd_tea575x_write(tea, tea->val); -+ for (;;) { -+ unsigned val = snd_tea575x_read(tea); -+ -+ if (!(val & TEA575X_BIT_SEARCH)) { -+ /* Found a frequency */ -+ val &= TEA575X_BIT_FREQ_MASK; -+ val = (val * 10) / 125; -+ if (tea->tea5759) -+ val += TEA575X_FMIF; -+ else -+ val -= TEA575X_FMIF; -+ tea->freq = clamp(val * 16, FREQ_LO, FREQ_HI); -+ return 0; -+ } -+ if (schedule_timeout_interruptible(msecs_to_jiffies(10))) { -+ /* some signal arrived, stop search */ -+ tea->val &= ~TEA575X_BIT_SEARCH; -+ snd_tea575x_write(tea, tea->val); -+ return -ERESTARTSYS; -+ } -+ } - return 0; - } - -@@ -273,23 +276,27 @@ static int tea575x_s_ctrl(struct v4l2_ct - static const struct v4l2_file_operations tea575x_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, -+ .open = v4l2_fh_open, -+ .release = v4l2_fh_release, -+ .poll = v4l2_ctrl_poll, - }; - - static const struct v4l2_ioctl_ops tea575x_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -+ .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, -+ .vidioc_log_status = v4l2_ctrl_log_status, -+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - }; - --static struct video_device tea575x_radio = { -- .name = "tea575x-tuner", -+static const struct video_device tea575x_radio = { - .fops = &tea575x_fops, - .ioctl_ops = &tea575x_ioctl_ops, -- .release = video_device_release_empty, -+ .release = video_device_release_empty, - }; - - static const struct v4l2_ctrl_ops tea575x_ctrl_ops = { -@@ -303,11 +310,15 @@ int snd_tea575x_init(struct snd_tea575x - { - int retval; - -- tea->mute = 1; -+ tea->mute = true; - -- snd_tea575x_write(tea, 0x55AA); -- if (snd_tea575x_read(tea) != 0x55AA) -- return -ENODEV; -+ /* Not all devices can or know how to read the data back. -+ Such devices can set cannot_read_data to true. */ -+ if (!tea->cannot_read_data) { -+ snd_tea575x_write(tea, 0x55AA); -+ if (snd_tea575x_read(tea) != 0x55AA) -+ return -ENODEV; -+ } - - tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40; - tea->freq = 90500 * 16; /* 90.5Mhz default */ -@@ -316,14 +327,17 @@ int snd_tea575x_init(struct snd_tea575x - tea->vd = tea575x_radio; - video_set_drvdata(&tea->vd, tea); - mutex_init(&tea->mutex); -+ strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); - tea->vd.lock = &tea->mutex; -+ tea->vd.v4l2_dev = tea->v4l2_dev; -+ tea->vd.ctrl_handler = &tea->ctrl_handler; -+ set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags); - - v4l2_ctrl_handler_init(&tea->ctrl_handler, 1); -- tea->vd.ctrl_handler = &tea->ctrl_handler; - v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); - retval = tea->ctrl_handler.error; - if (retval) { -- printk(KERN_ERR "tea575x-tuner: can't initialize controls\n"); -+ v4l2_err(tea->v4l2_dev, "can't initialize controls\n"); - v4l2_ctrl_handler_free(&tea->ctrl_handler); - return retval; - } -@@ -338,9 +352,9 @@ int snd_tea575x_init(struct snd_tea575x - - v4l2_ctrl_handler_setup(&tea->ctrl_handler); - -- retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, radio_nr); -+ retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr); - if (retval) { -- printk(KERN_ERR "tea575x-tuner: can't register video device!\n"); -+ v4l2_err(tea->v4l2_dev, "can't register video device!\n"); - v4l2_ctrl_handler_free(&tea->ctrl_handler); - return retval; - } -Index: linux-3.3.x86_64/sound/pci/es1968.c -=================================================================== ---- linux-3.3.x86_64.orig/sound/pci/es1968.c -+++ linux-3.3.x86_64/sound/pci/es1968.c -@@ -142,6 +142,7 @@ static int enable_mpu[SNDRV_CARDS] = {[0 - #ifdef SUPPORT_JOYSTICK - static bool joystick[SNDRV_CARDS]; - #endif -+static int radio_nr[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; - - module_param_array(index, int, NULL, 0444); - MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -@@ -165,6 +166,9 @@ MODULE_PARM_DESC(enable_mpu, "Enable MPU - module_param_array(joystick, bool, NULL, 0444); - MODULE_PARM_DESC(joystick, "Enable joystick."); - #endif -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); -+ - - - #define NR_APUS 64 -@@ -558,6 +562,7 @@ struct es1968 { - struct work_struct hwvol_work; - - #ifdef CONFIG_SND_ES1968_RADIO -+ struct v4l2_device v4l2_dev; - struct snd_tea575x tea; - #endif - }; -@@ -2613,6 +2618,7 @@ static int snd_es1968_free(struct es1968 - - #ifdef CONFIG_SND_ES1968_RADIO - snd_tea575x_exit(&chip->tea); -+ v4l2_device_unregister(&chip->v4l2_dev); - #endif - - if (chip->irq >= 0) -@@ -2655,6 +2661,7 @@ static int __devinit snd_es1968_create(s - int capt_streams, - int chip_type, - int do_pm, -+ int radio_nr, - struct es1968 **chip_ret) - { - static struct snd_device_ops ops = { -@@ -2751,7 +2758,14 @@ static int __devinit snd_es1968_create(s - snd_card_set_dev(card, &pci->dev); - - #ifdef CONFIG_SND_ES1968_RADIO -+ err = v4l2_device_register(&pci->dev, &chip->v4l2_dev); -+ if (err < 0) { -+ snd_es1968_free(chip); -+ return err; -+ } -+ chip->tea.v4l2_dev = &chip->v4l2_dev; - chip->tea.private_data = chip; -+ chip->tea.radio_nr = radio_nr; - chip->tea.ops = &snd_es1968_tea_ops; - strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card)); - sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); -@@ -2797,6 +2811,7 @@ static int __devinit snd_es1968_probe(st - pcm_substreams_c[dev], - pci_id->driver_data, - use_pm[dev], -+ radio_nr[dev], - &chip)) < 0) { - snd_card_free(card); - return err; -Index: linux-3.3.x86_64/sound/pci/fm801.c -=================================================================== ---- linux-3.3.x86_64.orig/sound/pci/fm801.c -+++ linux-3.3.x86_64/sound/pci/fm801.c -@@ -58,6 +58,7 @@ static bool enable[SNDRV_CARDS] = SNDRV_ - * High 16-bits are video (radio) device number + 1 - */ - static int tea575x_tuner[SNDRV_CARDS]; -+static int radio_nr[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; - - module_param_array(index, int, NULL, 0444); - MODULE_PARM_DESC(index, "Index value for the FM801 soundcard."); -@@ -67,6 +68,9 @@ module_param_array(enable, bool, NULL, 0 - MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); - module_param_array(tea575x_tuner, int, NULL, 0444); - MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only)."); -+module_param_array(radio_nr, int, NULL, 0444); -+MODULE_PARM_DESC(radio_nr, "Radio device numbers"); -+ - - #define TUNER_DISABLED (1<<3) - #define TUNER_ONLY (1<<4) -@@ -197,6 +201,7 @@ struct fm801 { - struct snd_info_entry *proc_entry; - - #ifdef CONFIG_SND_FM801_TEA575X_BOOL -+ struct v4l2_device v4l2_dev; - struct snd_tea575x tea; - #endif - -@@ -1154,8 +1159,10 @@ static int snd_fm801_free(struct fm801 * - - __end_hw: - #ifdef CONFIG_SND_FM801_TEA575X_BOOL -- if (!(chip->tea575x_tuner & TUNER_DISABLED)) -+ if (!(chip->tea575x_tuner & TUNER_DISABLED)) { - snd_tea575x_exit(&chip->tea); -+ v4l2_device_unregister(&chip->v4l2_dev); -+ } - #endif - if (chip->irq >= 0) - free_irq(chip->irq, chip); -@@ -1175,6 +1182,7 @@ static int snd_fm801_dev_free(struct snd - static int __devinit snd_fm801_create(struct snd_card *card, - struct pci_dev * pci, - int tea575x_tuner, -+ int radio_nr, - struct fm801 ** rchip) - { - struct fm801 *chip; -@@ -1234,6 +1242,13 @@ static int __devinit snd_fm801_create(st - snd_card_set_dev(card, &pci->dev); - - #ifdef CONFIG_SND_FM801_TEA575X_BOOL -+ err = v4l2_device_register(&pci->dev, &chip->v4l2_dev); -+ if (err < 0) { -+ snd_fm801_free(chip); -+ return err; -+ } -+ chip->tea.v4l2_dev = &chip->v4l2_dev; -+ chip->tea.radio_nr = radio_nr; - chip->tea.private_data = chip; - chip->tea.ops = &snd_fm801_tea_ops; - sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); -@@ -1241,6 +1256,7 @@ static int __devinit snd_fm801_create(st - (tea575x_tuner & TUNER_TYPE_MASK) < 4) { - if (snd_tea575x_init(&chip->tea)) { - snd_printk(KERN_ERR "TEA575x radio not found\n"); -+ snd_fm801_free(chip); - return -ENODEV; - } - } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) { -@@ -1287,7 +1303,7 @@ static int __devinit snd_card_fm801_prob - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); - if (err < 0) - return err; -- if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], &chip)) < 0) { -+ if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip)) < 0) { - snd_card_free(card); - return err; - } -Index: linux-3.3.x86_64/drivers/media/radio/radio-maxiradio.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/radio/radio-maxiradio.c -+++ linux-3.3.x86_64/drivers/media/radio/radio-maxiradio.c -@@ -42,67 +42,37 @@ - #include - #include - #include -+#include - #include - #include -- --#define DRIVER_VERSION "0.7.8" -- -+#include -+#include -+#include - - MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); --MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); -+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000."); - MODULE_LICENSE("GPL"); --MODULE_VERSION(DRIVER_VERSION); -+MODULE_VERSION("1.0.0"); - - static int radio_nr = -1; --module_param(radio_nr, int, 0); -- --static int debug; -- --module_param(debug, int, 0644); --MODULE_PARM_DESC(debug, "activates debug info"); -- --#define dprintk(dev, num, fmt, arg...) \ -- v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg) -- --#ifndef PCI_VENDOR_ID_GUILLEMOT --#define PCI_VENDOR_ID_GUILLEMOT 0x5046 --#endif -- --#ifndef PCI_DEVICE_ID_GUILLEMOT --#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 --#endif -- -+module_param(radio_nr, int, 0644); -+MODULE_PARM_DESC(radio_nr, "Radio device number"); - - /* TEA5757 pin mappings */ - static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; - --#define FREQ_LO (87 * 16000) --#define FREQ_HI (108 * 16000) -- --#define FREQ_IF 171200 /* 10.7*16000 */ --#define FREQ_STEP 200 /* 12.5*16 */ -- --/* (x==fmhz*16*1000) -> bits */ --#define FREQ2BITS(x) \ -- ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2) -- --#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) -+static atomic_t maxiradio_instance = ATOMIC_INIT(0); - -+#define PCI_VENDOR_ID_GUILLEMOT 0x5046 -+#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 - - struct maxiradio - { -+ struct snd_tea575x tea; - struct v4l2_device v4l2_dev; -- struct video_device vdev; - struct pci_dev *pdev; - - u16 io; /* base of radio io */ -- u16 muted; /* VIDEO_AUDIO_MUTE */ -- u16 stereo; /* VIDEO_TUNER_STEREO_ON */ -- u16 tuned; /* signal strength (0 or 0xffff) */ -- -- unsigned long freq; -- -- struct mutex lock; - }; - - static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) -@@ -110,259 +80,41 @@ static inline struct maxiradio *to_maxir - return container_of(v4l2_dev, struct maxiradio, v4l2_dev); - } - --static void outbit(unsigned long bit, u16 io) --{ -- int val = power | wren | (bit ? data : 0); -- -- outb(val, io); -- udelay(4); -- outb(val | clk, io); -- udelay(4); -- outb(val, io); -- udelay(4); --} -- --static void turn_power(struct maxiradio *dev, int p) --{ -- if (p != 0) { -- dprintk(dev, 1, "Radio powered on\n"); -- outb(power, dev->io); -- } else { -- dprintk(dev, 1, "Radio powered off\n"); -- outb(0, dev->io); -- } --} -- --static void set_freq(struct maxiradio *dev, u32 freq) --{ -- unsigned long int si; -- int bl; -- int io = dev->io; -- int val = FREQ2BITS(freq); -- -- /* TEA5757 shift register bits (see pdf) */ -- -- outbit(0, io); /* 24 search */ -- outbit(1, io); /* 23 search up/down */ -- -- outbit(0, io); /* 22 stereo/mono */ -- -- outbit(0, io); /* 21 band */ -- outbit(0, io); /* 20 band (only 00=FM works I think) */ -- -- outbit(0, io); /* 19 port ? */ -- outbit(0, io); /* 18 port ? */ -- -- outbit(0, io); /* 17 search level */ -- outbit(0, io); /* 16 search level */ -- -- si = 0x8000; -- for (bl = 1; bl <= 16; bl++) { -- outbit(val & si, io); -- si >>= 1; -- } -- -- dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n", -- freq / 16000, -- freq % 16000 * 100 / 16000); -- -- turn_power(dev, 1); --} -- --static int get_stereo(u16 io) --{ -- outb(power,io); -- udelay(4); -- -- return !(inb(io) & mo_st); --} -- --static int get_tune(u16 io) --{ -- outb(power+clk,io); -- udelay(4); -- -- return !(inb(io) & mo_st); --} -- -- --static int vidioc_querycap(struct file *file, void *priv, -- struct v4l2_capability *v) --{ -- struct maxiradio *dev = video_drvdata(file); -- -- strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver)); -- strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card)); -- snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); -- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; -- return 0; --} -- --static int vidioc_g_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) -+static void maxiradio_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) - { -- struct maxiradio *dev = video_drvdata(file); -+ struct maxiradio *dev = tea->private_data; -+ u8 bits = 0; - -- if (v->index > 0) -- return -EINVAL; -+ bits |= (pins & TEA575X_DATA) ? data : 0; -+ bits |= (pins & TEA575X_CLK) ? clk : 0; -+ bits |= (pins & TEA575X_WREN) ? wren : 0; -+ bits |= power; - -- mutex_lock(&dev->lock); -- strlcpy(v->name, "FM", sizeof(v->name)); -- v->type = V4L2_TUNER_RADIO; -- v->rangelow = FREQ_LO; -- v->rangehigh = FREQ_HI; -- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; -- v->capability = V4L2_TUNER_CAP_LOW; -- if (get_stereo(dev->io)) -- v->audmode = V4L2_TUNER_MODE_STEREO; -- else -- v->audmode = V4L2_TUNER_MODE_MONO; -- v->signal = 0xffff * get_tune(dev->io); -- mutex_unlock(&dev->lock); -- -- return 0; --} -- --static int vidioc_s_tuner(struct file *file, void *priv, -- struct v4l2_tuner *v) --{ -- return v->index ? -EINVAL : 0; --} -- --static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) --{ -- *i = 0; -- return 0; --} -- --static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) --{ -- return i ? -EINVAL : 0; --} -- --static int vidioc_g_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- a->index = 0; -- strlcpy(a->name, "Radio", sizeof(a->name)); -- a->capability = V4L2_AUDCAP_STEREO; -- return 0; --} -- -- --static int vidioc_s_audio(struct file *file, void *priv, -- struct v4l2_audio *a) --{ -- return a->index ? -EINVAL : 0; --} -- --static int vidioc_s_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct maxiradio *dev = video_drvdata(file); -- -- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- return -EINVAL; -- if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { -- dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", -- f->frequency / 16000, -- f->frequency % 16000 * 100 / 16000, -- FREQ_LO / 16000, FREQ_HI / 16000); -- -- return -EINVAL; -- } -- -- mutex_lock(&dev->lock); -- dev->freq = f->frequency; -- set_freq(dev, dev->freq); -- msleep(125); -- mutex_unlock(&dev->lock); -- -- return 0; --} -- --static int vidioc_g_frequency(struct file *file, void *priv, -- struct v4l2_frequency *f) --{ -- struct maxiradio *dev = video_drvdata(file); -- -- if (f->tuner != 0) -- return -EINVAL; -- f->type = V4L2_TUNER_RADIO; -- f->frequency = dev->freq; -- -- dprintk(dev, 4, "radio freq is %d.%02d MHz", -- f->frequency / 16000, -- f->frequency % 16000 * 100 / 16000); -- -- return 0; --} -- --static int vidioc_queryctrl(struct file *file, void *priv, -- struct v4l2_queryctrl *qc) --{ -- switch (qc->id) { -- case V4L2_CID_AUDIO_MUTE: -- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); -- } -- return -EINVAL; -+ outb(bits, dev->io); - } - --static int vidioc_g_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) -+/* Note: this card cannot read out the data of the shift registers, -+ only the mono/stereo pin works. */ -+static u8 maxiradio_tea575x_get_pins(struct snd_tea575x *tea) - { -- struct maxiradio *dev = video_drvdata(file); -+ struct maxiradio *dev = tea->private_data; -+ u8 bits = inb(dev->io); - -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- ctrl->value = dev->muted; -- return 0; -- } -- -- return -EINVAL; -+ return ((bits & data) ? TEA575X_DATA : 0) | -+ ((bits & mo_st) ? TEA575X_MOST : 0); - } - --static int vidioc_s_ctrl(struct file *file, void *priv, -- struct v4l2_control *ctrl) -+static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output) - { -- struct maxiradio *dev = video_drvdata(file); -- -- switch (ctrl->id) { -- case V4L2_CID_AUDIO_MUTE: -- mutex_lock(&dev->lock); -- dev->muted = ctrl->value; -- if (dev->muted) -- turn_power(dev, 0); -- else -- set_freq(dev, dev->freq); -- mutex_unlock(&dev->lock); -- return 0; -- } -- -- return -EINVAL; - } - --static const struct v4l2_file_operations maxiradio_fops = { -- .owner = THIS_MODULE, -- .unlocked_ioctl = video_ioctl2, --}; -- --static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { -- .vidioc_querycap = vidioc_querycap, -- .vidioc_g_tuner = vidioc_g_tuner, -- .vidioc_s_tuner = vidioc_s_tuner, -- .vidioc_g_audio = vidioc_g_audio, -- .vidioc_s_audio = vidioc_s_audio, -- .vidioc_g_input = vidioc_g_input, -- .vidioc_s_input = vidioc_s_input, -- .vidioc_g_frequency = vidioc_g_frequency, -- .vidioc_s_frequency = vidioc_s_frequency, -- .vidioc_queryctrl = vidioc_queryctrl, -- .vidioc_g_ctrl = vidioc_g_ctrl, -- .vidioc_s_ctrl = vidioc_s_ctrl, -+static struct snd_tea575x_ops maxiradio_tea_ops = { -+ .set_pins = maxiradio_tea575x_set_pins, -+ .get_pins = maxiradio_tea575x_get_pins, -+ .set_direction = maxiradio_tea575x_set_direction, - }; - --static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -+static int __devinit maxiradio_probe(struct pci_dev *pdev, const struct pci_device_id *ent) - { - struct maxiradio *dev; - struct v4l2_device *v4l2_dev; -@@ -375,63 +127,60 @@ static int __devinit maxiradio_init_one( - } - - v4l2_dev = &dev->v4l2_dev; -- mutex_init(&dev->lock); -- dev->pdev = pdev; -- dev->muted = 1; -- dev->freq = FREQ_LO; -- -- strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name)); -+ v4l2_device_set_name(v4l2_dev, "maxiradio", &maxiradio_instance); - - retval = v4l2_device_register(&pdev->dev, v4l2_dev); - if (retval < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - goto errfr; - } -+ dev->tea.private_data = dev; -+ dev->tea.ops = &maxiradio_tea_ops; -+ /* The data pin cannot be read. This may be a hardware limitation, or -+ we just don't know how to read it. */ -+ dev->tea.cannot_read_data = true; -+ dev->tea.v4l2_dev = v4l2_dev; -+ dev->tea.radio_nr = radio_nr; -+ strlcpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card)); -+ snprintf(dev->tea.bus_info, sizeof(dev->tea.bus_info), -+ "PCI:%s", pci_name(pdev)); -+ -+ retval = -ENODEV; - - if (!request_region(pci_resource_start(pdev, 0), -- pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { -- v4l2_err(v4l2_dev, "can't reserve I/O ports\n"); -- goto err_out; -+ pci_resource_len(pdev, 0), v4l2_dev->name)) { -+ dev_err(&pdev->dev, "can't reserve I/O ports\n"); -+ goto err_hdl; - } - - if (pci_enable_device(pdev)) - goto err_out_free_region; - - dev->io = pci_resource_start(pdev, 0); -- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); -- dev->vdev.v4l2_dev = v4l2_dev; -- dev->vdev.fops = &maxiradio_fops; -- dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; -- dev->vdev.release = video_device_release_empty; -- video_set_drvdata(&dev->vdev, dev); -- -- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { -- v4l2_err(v4l2_dev, "can't register device!"); -+ if (snd_tea575x_init(&dev->tea)) { -+ printk(KERN_ERR "radio-maxiradio: Unable to detect TEA575x tuner\n"); - goto err_out_free_region; - } -- -- v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); -- -- v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n", -- dev->io); - return 0; - - err_out_free_region: - release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); --err_out: -+err_hdl: - v4l2_device_unregister(v4l2_dev); - errfr: - kfree(dev); -- return -ENODEV; -+ return retval; - } - --static void __devexit maxiradio_remove_one(struct pci_dev *pdev) -+static void __devexit maxiradio_remove(struct pci_dev *pdev) - { - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct maxiradio *dev = to_maxiradio(v4l2_dev); - -- video_unregister_device(&dev->vdev); -- v4l2_device_unregister(&dev->v4l2_dev); -+ snd_tea575x_exit(&dev->tea); -+ /* Turn off power */ -+ outb(0, dev->io); -+ v4l2_device_unregister(v4l2_dev); - release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - } - -@@ -446,19 +195,19 @@ MODULE_DEVICE_TABLE(pci, maxiradio_pci_t - static struct pci_driver maxiradio_driver = { - .name = "radio-maxiradio", - .id_table = maxiradio_pci_tbl, -- .probe = maxiradio_init_one, -- .remove = __devexit_p(maxiradio_remove_one), -+ .probe = maxiradio_probe, -+ .remove = __devexit_p(maxiradio_remove), - }; - --static int __init maxiradio_radio_init(void) -+static int __init maxiradio_init(void) - { - return pci_register_driver(&maxiradio_driver); - } - --static void __exit maxiradio_radio_exit(void) -+static void __exit maxiradio_exit(void) - { - pci_unregister_driver(&maxiradio_driver); - } - --module_init(maxiradio_radio_init); --module_exit(maxiradio_radio_exit); -+module_init(maxiradio_init); -+module_exit(maxiradio_exit); -Index: linux-3.3.x86_64/include/media/v4l2-dev.h -=================================================================== ---- linux-3.3.x86_64.orig/include/media/v4l2-dev.h -+++ linux-3.3.x86_64/include/media/v4l2-dev.h -@@ -62,6 +62,9 @@ struct v4l2_file_operations { - unsigned int (*poll) (struct file *, struct poll_table_struct *); - long (*ioctl) (struct file *, unsigned int, unsigned long); - long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); -+#ifdef CONFIG_COMPAT -+ long (*compat_ioctl32) (struct file *, unsigned int, unsigned long); -+#endif - unsigned long (*get_unmapped_area) (struct file *, unsigned long, - unsigned long, unsigned long, unsigned long); - int (*mmap) (struct file *, struct vm_area_struct *); -Index: linux-3.3.x86_64/drivers/media/video/uvc/uvc_v4l2.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/uvc/uvc_v4l2.c -+++ linux-3.3.x86_64/drivers/media/video/uvc/uvc_v4l2.c -@@ -11,6 +11,7 @@ - * - */ - -+#include - #include - #include - #include -@@ -1012,7 +1013,7 @@ static long uvc_v4l2_do_ioctl(struct fil - - default: - uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd); -- return -EINVAL; -+ return -ENOTTY; - } - - return ret; -@@ -1030,6 +1031,207 @@ static long uvc_v4l2_ioctl(struct file * - return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); - } - -+#ifdef CONFIG_COMPAT -+struct uvc_xu_control_mapping32 { -+ __u32 id; -+ __u8 name[32]; -+ __u8 entity[16]; -+ __u8 selector; -+ -+ __u8 size; -+ __u8 offset; -+ __u32 v4l2_type; -+ __u32 data_type; -+ -+ compat_caddr_t menu_info; -+ __u32 menu_count; -+ -+ __u32 reserved[4]; -+}; -+ -+static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp, -+ const struct uvc_xu_control_mapping32 __user *up) -+{ -+ struct uvc_menu_info __user *umenus; -+ struct uvc_menu_info __user *kmenus; -+ compat_caddr_t p; -+ -+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || -+ __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) || -+ __get_user(kp->menu_count, &up->menu_count)) -+ return -EFAULT; -+ -+ memset(kp->reserved, 0, sizeof(kp->reserved)); -+ -+ if (kp->menu_count == 0) { -+ kp->menu_info = NULL; -+ return 0; -+ } -+ -+ if (__get_user(p, &up->menu_info)) -+ return -EFAULT; -+ umenus = compat_ptr(p); -+ if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus))) -+ return -EFAULT; -+ -+ kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus)); -+ if (kmenus == NULL) -+ return -EFAULT; -+ kp->menu_info = kmenus; -+ -+ if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus))) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp, -+ struct uvc_xu_control_mapping32 __user *up) -+{ -+ struct uvc_menu_info __user *umenus; -+ struct uvc_menu_info __user *kmenus = kp->menu_info; -+ compat_caddr_t p; -+ -+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || -+ __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) || -+ __put_user(kp->menu_count, &up->menu_count)) -+ return -EFAULT; -+ -+ __clear_user(up->reserved, sizeof(up->reserved)); -+ -+ if (kp->menu_count == 0) -+ return 0; -+ -+ if (get_user(p, &up->menu_info)) -+ return -EFAULT; -+ umenus = compat_ptr(p); -+ if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus))) -+ return -EFAULT; -+ -+ if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus))) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+struct uvc_xu_control_query32 { -+ __u8 unit; -+ __u8 selector; -+ __u8 query; -+ __u16 size; -+ compat_caddr_t data; -+}; -+ -+static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp, -+ const struct uvc_xu_control_query32 __user *up) -+{ -+ u8 __user *udata; -+ u8 __user *kdata; -+ compat_caddr_t p; -+ -+ if (!access_ok(VERIFY_READ, up, sizeof(*up)) || -+ __copy_from_user(kp, up, offsetof(typeof(*up), data))) -+ return -EFAULT; -+ -+ if (kp->size == 0) { -+ kp->data = NULL; -+ return 0; -+ } -+ -+ if (__get_user(p, &up->data)) -+ return -EFAULT; -+ udata = compat_ptr(p); -+ if (!access_ok(VERIFY_READ, udata, kp->size)) -+ return -EFAULT; -+ -+ kdata = compat_alloc_user_space(kp->size); -+ if (kdata == NULL) -+ return -EFAULT; -+ kp->data = kdata; -+ -+ if (copy_in_user(kdata, udata, kp->size)) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, -+ struct uvc_xu_control_query32 __user *up) -+{ -+ u8 __user *udata; -+ u8 __user *kdata = kp->data; -+ compat_caddr_t p; -+ -+ if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) || -+ __copy_to_user(up, kp, offsetof(typeof(*up), data))) -+ return -EFAULT; -+ -+ if (kp->size == 0) -+ return 0; -+ -+ if (get_user(p, &up->data)) -+ return -EFAULT; -+ udata = compat_ptr(p); -+ if (!access_ok(VERIFY_READ, udata, kp->size)) -+ return -EFAULT; -+ -+ if (copy_in_user(udata, kdata, kp->size)) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+#define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32) -+#define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32) -+ -+static long uvc_v4l2_compat_ioctl32(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ union { -+ struct uvc_xu_control_mapping xmap; -+ struct uvc_xu_control_query xqry; -+ } karg; -+ void __user *up = compat_ptr(arg); -+ mm_segment_t old_fs; -+ long ret; -+ -+ switch (cmd) { -+ case UVCIOC_CTRL_MAP32: -+ cmd = UVCIOC_CTRL_MAP; -+ ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); -+ break; -+ -+ case UVCIOC_CTRL_QUERY32: -+ cmd = UVCIOC_CTRL_QUERY; -+ ret = uvc_v4l2_get_xu_query(&karg.xqry, up); -+ break; -+ -+ default: -+ return -ENOIOCTLCMD; -+ } -+ -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg); -+ set_fs(old_fs); -+ -+ if (ret < 0) -+ return ret; -+ -+ switch (cmd) { -+ case UVCIOC_CTRL_MAP: -+ ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); -+ break; -+ -+ case UVCIOC_CTRL_QUERY: -+ ret = uvc_v4l2_put_xu_query(&karg.xqry, up); -+ break; -+ } -+ -+ return ret; -+} -+#endif -+ - static ssize_t uvc_v4l2_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) - { -@@ -1076,6 +1278,9 @@ const struct v4l2_file_operations uvc_fo - .open = uvc_v4l2_open, - .release = uvc_v4l2_release, - .unlocked_ioctl = uvc_v4l2_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl32 = uvc_v4l2_compat_ioctl32, -+#endif - .read = uvc_v4l2_read, - .mmap = uvc_v4l2_mmap, - .poll = uvc_v4l2_poll, -Index: linux-3.3.x86_64/drivers/media/video/uvc/uvc_queue.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/uvc/uvc_queue.c -+++ linux-3.3.x86_64/drivers/media/video/uvc/uvc_queue.c -@@ -126,7 +126,7 @@ void uvc_queue_init(struct uvc_video_que - int drop_corrupted) - { - queue->queue.type = type; -- queue->queue.io_modes = VB2_MMAP; -+ queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; - queue->queue.drv_priv = queue; - queue->queue.buf_struct_size = sizeof(struct uvc_buffer); - queue->queue.ops = &uvc_queue_qops; -Index: linux-3.3.x86_64/drivers/media/video/uvc/uvc_driver.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/uvc/uvc_driver.c -+++ linux-3.3.x86_64/drivers/media/video/uvc/uvc_driver.c -@@ -23,6 +23,7 @@ - * codec can't handle MJPEG data. - */ - -+#include - #include - #include - #include -@@ -32,7 +33,6 @@ - #include - #include - #include --#include - #include - - #include -@@ -2139,6 +2139,15 @@ static struct usb_device_id uvc_ids[] = - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, -+ /* Dell XPS m1530 */ -+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE -+ | USB_DEVICE_ID_MATCH_INT_INFO, -+ .idVendor = 0x05a9, -+ .idProduct = 0x2640, -+ .bInterfaceClass = USB_CLASS_VIDEO, -+ .bInterfaceSubClass = 1, -+ .bInterfaceProtocol = 0, -+ .driver_info = UVC_QUIRK_PROBE_DEF }, - /* Apple Built-In iSight */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/stv0288.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/stv0288.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/stv0288.c -@@ -506,7 +506,7 @@ static int stv0288_set_frontend(struct d - tda[1] = (unsigned char)tm; - stv0288_writeregI(state, 0x2b, tda[1]); - stv0288_writeregI(state, 0x2c, tda[2]); -- udelay(30); -+ msleep(30); - } - state->tuner_frequency = c->frequency; - state->fec_inner = FEC_AUTO; -Index: linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-cards.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx231xx/cx231xx-cards.c -+++ linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-cards.c -@@ -861,7 +861,6 @@ void cx231xx_release_resources(struct cx - kfree(dev->sliced_cc_mode.alt_max_pkt_size); - kfree(dev->ts1_mode.alt_max_pkt_size); - kfree(dev); -- dev = NULL; - } - - /* -Index: linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-video.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/cx231xx/cx231xx-video.c -+++ linux-3.3.x86_64/drivers/media/video/cx231xx/cx231xx-video.c -@@ -2319,8 +2319,7 @@ static int cx231xx_v4l2_close(struct fil - if (dev->state & DEV_DISCONNECTED) { - if (atomic_read(&dev->devlist_count) > 0) { - cx231xx_release_resources(dev); -- kfree(dev); -- dev = NULL; -+ fh->dev = NULL; - return 0; - } - return 0; -@@ -2350,8 +2349,7 @@ static int cx231xx_v4l2_close(struct fil - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - cx231xx_release_resources(dev); -- kfree(dev); -- dev = NULL; -+ fh->dev = NULL; - return 0; - } - -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/dib9000.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/dib9000.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/dib9000.c -@@ -33,7 +33,7 @@ struct i2c_device { - - /* lock */ - #define DIB_LOCK struct mutex --#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0) -+#define DibAcquireLock(lock) mutex_lock_interruptible(lock) - #define DibReleaseLock(lock) mutex_unlock(lock) - #define DibInitLock(lock) mutex_init(lock) - #define DibFreeLock(lock) -@@ -446,7 +446,10 @@ static int dib9000_risc_mem_read(struct - if (!state->platform.risc.fw_is_running) - return -EIO; - -- DibAcquireLock(&state->platform.risc.mem_lock); -+ if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - dib9000_risc_mem_setup(state, cmd | 0x80); - dib9000_risc_mem_read_chunks(state, b, len); - DibReleaseLock(&state->platform.risc.mem_lock); -@@ -459,7 +462,10 @@ static int dib9000_risc_mem_write(struct - if (!state->platform.risc.fw_is_running) - return -EIO; - -- DibAcquireLock(&state->platform.risc.mem_lock); -+ if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - dib9000_risc_mem_setup(state, cmd); - dib9000_risc_mem_write_chunks(state, b, m->size); - DibReleaseLock(&state->platform.risc.mem_lock); -@@ -531,7 +537,10 @@ static int dib9000_mbx_send_attr(struct - if (!state->platform.risc.fw_is_running) - return -EINVAL; - -- DibAcquireLock(&state->platform.risc.mbx_if_lock); -+ if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - tmp = MAX_MAILBOX_TRY; - do { - size = dib9000_read_word_attr(state, 1043, attr) & 0xff; -@@ -593,7 +602,10 @@ static u8 dib9000_mbx_read(struct dib900 - if (!state->platform.risc.fw_is_running) - return 0; - -- DibAcquireLock(&state->platform.risc.mbx_if_lock); -+ if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) { -+ dprintk("could not get the lock"); -+ return 0; -+ } - if (risc_id == 1) - mc_base = 16; - else -@@ -701,7 +713,10 @@ static int dib9000_mbx_process(struct di - if (!state->platform.risc.fw_is_running) - return -1; - -- DibAcquireLock(&state->platform.risc.mbx_lock); -+ if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -1; -+ } - - if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ - ret = dib9000_mbx_fetch_to_cache(state, attr); -@@ -1178,7 +1193,10 @@ static int dib9000_fw_get_channel(struct - struct dibDVBTChannel *ch; - int ret = 0; - -- DibAcquireLock(&state->platform.risc.mem_mbx_lock); -+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - ret = -EIO; - goto error; -@@ -1660,7 +1678,10 @@ static int dib9000_fw_component_bus_xfer - p[12] = 0; - } - -- DibAcquireLock(&state->platform.risc.mem_mbx_lock); -+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { -+ dprintk("could not get the lock"); -+ return 0; -+ } - - dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); - -@@ -1768,7 +1789,10 @@ int dib9000_fw_pid_filter_ctrl(struct dv - return 0; - } - -- DibAcquireLock(&state->demod_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - - val = dib9000_read_word(state, 294 + 1) & 0xffef; - val |= (onoff & 0x1) << 4; -@@ -1800,7 +1824,10 @@ int dib9000_fw_pid_filter(struct dvb_fro - return 0; - } - -- DibAcquireLock(&state->demod_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); - ret = dib9000_write_word(state, 300 + 1 + id, - onoff ? (1 << 13) | pid : 0); -@@ -1848,7 +1875,10 @@ static int dib9000_sleep(struct dvb_fron - u8 index_frontend; - int ret = 0; - -- DibAcquireLock(&state->demod_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); - if (ret < 0) -@@ -1874,8 +1904,12 @@ static int dib9000_get_frontend(struct d - fe_status_t stat; - int ret = 0; - -- if (state->get_frontend_internal == 0) -- DibAcquireLock(&state->demod_lock); -+ if (state->get_frontend_internal == 0) { -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } -+ } - - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); -@@ -1978,7 +2012,10 @@ static int dib9000_set_frontend(struct d - } - - state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ -- DibAcquireLock(&state->demod_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return 0; -+ } - - fe->dtv_property_cache.delivery_system = SYS_DVBT; - -@@ -2138,7 +2175,10 @@ static int dib9000_read_status(struct dv - u8 index_frontend; - u16 lock = 0, lock_slave = 0; - -- DibAcquireLock(&state->demod_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - lock_slave |= dib9000_read_lock(state->fe[index_frontend]); - -@@ -2168,8 +2208,15 @@ static int dib9000_read_ber(struct dvb_f - u16 *c; - int ret = 0; - -- DibAcquireLock(&state->demod_lock); -- DibAcquireLock(&state->platform.risc.mem_mbx_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } -+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { -+ dprintk("could not get the lock"); -+ ret = -EINTR; -+ goto error; -+ } - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - ret = -EIO; -@@ -2196,7 +2243,10 @@ static int dib9000_read_signal_strength( - u16 val; - int ret = 0; - -- DibAcquireLock(&state->demod_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - *strength = 0; - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); -@@ -2206,8 +2256,13 @@ static int dib9000_read_signal_strength( - *strength += val; - } - -- DibAcquireLock(&state->platform.risc.mem_mbx_lock); -+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { -+ dprintk("could not get the lock"); -+ ret = -EINTR; -+ goto error; -+ } - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { -+ DibReleaseLock(&state->platform.risc.mem_mbx_lock); - ret = -EIO; - goto error; - } -@@ -2232,9 +2287,14 @@ static u32 dib9000_get_snr(struct dvb_fr - u32 n, s, exp; - u16 val; - -- DibAcquireLock(&state->platform.risc.mem_mbx_lock); -- if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) -- return -EIO; -+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { -+ dprintk("could not get the lock"); -+ return 0; -+ } -+ if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { -+ DibReleaseLock(&state->platform.risc.mem_mbx_lock); -+ return 0; -+ } - dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); - DibReleaseLock(&state->platform.risc.mem_mbx_lock); - -@@ -2266,7 +2326,10 @@ static int dib9000_read_snr(struct dvb_f - u8 index_frontend; - u32 snr_master; - -- DibAcquireLock(&state->demod_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } - snr_master = dib9000_get_snr(fe); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - snr_master += dib9000_get_snr(state->fe[index_frontend]); -@@ -2288,9 +2351,17 @@ static int dib9000_read_unc_blocks(struc - u16 *c = (u16 *)state->i2c_read_buffer; - int ret = 0; - -- DibAcquireLock(&state->demod_lock); -- DibAcquireLock(&state->platform.risc.mem_mbx_lock); -+ if (DibAcquireLock(&state->demod_lock) < 0) { -+ dprintk("could not get the lock"); -+ return -EINTR; -+ } -+ if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) { -+ dprintk("could not get the lock"); -+ ret = -EINTR; -+ goto error; -+ } - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { -+ DibReleaseLock(&state->platform.risc.mem_mbx_lock); - ret = -EIO; - goto error; - } -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/drxd_hard.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/drxd_hard.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/drxd_hard.c -@@ -101,9 +101,9 @@ struct SCfgAgc { - - struct SNoiseCal { - int cpOpt; -- u16 cpNexpOfs; -- u16 tdCal2k; -- u16 tdCal8k; -+ short cpNexpOfs; -+ short tdCal2k; -+ short tdCal8k; - }; - - enum app_env { -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/m88rs2000.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/m88rs2000.c -@@ -0,0 +1,904 @@ -+/* -+ Driver for M88RS2000 demodulator and tuner -+ -+ Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com) -+ Beta Driver -+ -+ Include various calculation code from DS3000 driver. -+ Copyright (C) 2009 Konstantin Dimitrov. -+ -+ 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 -+#include -+ -+ -+#include "dvb_frontend.h" -+#include "m88rs2000.h" -+ -+struct m88rs2000_state { -+ struct i2c_adapter *i2c; -+ const struct m88rs2000_config *config; -+ struct dvb_frontend frontend; -+ u8 no_lock_count; -+ u32 tuner_frequency; -+ u32 symbol_rate; -+ fe_code_rate_t fec_inner; -+ u8 tuner_level; -+ int errmode; -+}; -+ -+static int m88rs2000_debug; -+ -+module_param_named(debug, m88rs2000_debug, int, 0644); -+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); -+ -+#define dprintk(level, args...) do { \ -+ if (level & m88rs2000_debug) \ -+ printk(KERN_DEBUG "m88rs2000-fe: " args); \ -+} while (0) -+ -+#define deb_info(args...) dprintk(0x01, args) -+#define info(format, arg...) \ -+ printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg) -+ -+static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner, -+ u8 reg, u8 data) -+{ -+ int ret; -+ u8 addr = (tuner == 0) ? state->config->tuner_addr : -+ state->config->demod_addr; -+ u8 buf[] = { reg, data }; -+ struct i2c_msg msg = { -+ .addr = addr, -+ .flags = 0, -+ .buf = buf, -+ .len = 2 -+ }; -+ -+ ret = i2c_transfer(state->i2c, &msg, 1); -+ -+ if (ret != 1) -+ deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, " -+ "ret == %i)\n", __func__, reg, data, ret); -+ -+ return (ret != 1) ? -EREMOTEIO : 0; -+} -+ -+static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data) -+{ -+ return m88rs2000_writereg(state, 1, reg, data); -+} -+ -+static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data) -+{ -+ m88rs2000_demod_write(state, 0x81, 0x84); -+ udelay(10); -+ return m88rs2000_writereg(state, 0, reg, data); -+ -+} -+ -+static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ -+ if (len != 2) -+ return -EINVAL; -+ -+ return m88rs2000_writereg(state, 1, buf[0], buf[1]); -+} -+ -+static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg) -+{ -+ int ret; -+ u8 b0[] = { reg }; -+ u8 b1[] = { 0 }; -+ u8 addr = (tuner == 0) ? state->config->tuner_addr : -+ state->config->demod_addr; -+ struct i2c_msg msg[] = { -+ { -+ .addr = addr, -+ .flags = 0, -+ .buf = b0, -+ .len = 1 -+ }, { -+ .addr = addr, -+ .flags = I2C_M_RD, -+ .buf = b1, -+ .len = 1 -+ } -+ }; -+ -+ ret = i2c_transfer(state->i2c, msg, 2); -+ -+ if (ret != 2) -+ deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n", -+ __func__, reg, ret); -+ -+ return b1[0]; -+} -+ -+static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg) -+{ -+ return m88rs2000_readreg(state, 1, reg); -+} -+ -+static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg) -+{ -+ m88rs2000_demod_write(state, 0x81, 0x85); -+ udelay(10); -+ return m88rs2000_readreg(state, 0, reg); -+} -+ -+static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ int ret; -+ u32 temp; -+ u8 b[3]; -+ -+ if ((srate < 1000000) || (srate > 45000000)) -+ return -EINVAL; -+ -+ temp = srate / 1000; -+ temp *= 11831; -+ temp /= 68; -+ temp -= 3; -+ -+ b[0] = (u8) (temp >> 16) & 0xff; -+ b[1] = (u8) (temp >> 8) & 0xff; -+ b[2] = (u8) temp & 0xff; -+ ret = m88rs2000_demod_write(state, 0x93, b[2]); -+ ret |= m88rs2000_demod_write(state, 0x94, b[1]); -+ ret |= m88rs2000_demod_write(state, 0x95, b[0]); -+ -+ deb_info("m88rs2000: m88rs2000_set_symbolrate\n"); -+ return ret; -+} -+ -+static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe, -+ struct dvb_diseqc_master_cmd *m) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ -+ int i; -+ u8 reg; -+ deb_info("%s\n", __func__); -+ m88rs2000_demod_write(state, 0x9a, 0x30); -+ reg = m88rs2000_demod_read(state, 0xb2); -+ reg &= 0x3f; -+ m88rs2000_demod_write(state, 0xb2, reg); -+ for (i = 0; i < m->msg_len; i++) -+ m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]); -+ -+ reg = m88rs2000_demod_read(state, 0xb1); -+ reg &= 0x87; -+ reg |= ((m->msg_len - 1) << 3) | 0x07; -+ reg &= 0x7f; -+ m88rs2000_demod_write(state, 0xb1, reg); -+ -+ for (i = 0; i < 15; i++) { -+ if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0) -+ break; -+ msleep(20); -+ } -+ -+ reg = m88rs2000_demod_read(state, 0xb1); -+ if ((reg & 0x40) > 0x0) { -+ reg &= 0x7f; -+ reg |= 0x40; -+ m88rs2000_demod_write(state, 0xb1, reg); -+ } -+ -+ reg = m88rs2000_demod_read(state, 0xb2); -+ reg &= 0x3f; -+ reg |= 0x80; -+ m88rs2000_demod_write(state, 0xb2, reg); -+ m88rs2000_demod_write(state, 0x9a, 0xb0); -+ -+ -+ return 0; -+} -+ -+static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe, -+ fe_sec_mini_cmd_t burst) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ u8 reg0, reg1; -+ deb_info("%s\n", __func__); -+ m88rs2000_demod_write(state, 0x9a, 0x30); -+ msleep(50); -+ reg0 = m88rs2000_demod_read(state, 0xb1); -+ reg1 = m88rs2000_demod_read(state, 0xb2); -+ /* TODO complete this section */ -+ m88rs2000_demod_write(state, 0xb2, reg1); -+ m88rs2000_demod_write(state, 0xb1, reg0); -+ m88rs2000_demod_write(state, 0x9a, 0xb0); -+ -+ return 0; -+} -+ -+static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ u8 reg0, reg1; -+ m88rs2000_demod_write(state, 0x9a, 0x30); -+ reg0 = m88rs2000_demod_read(state, 0xb1); -+ reg1 = m88rs2000_demod_read(state, 0xb2); -+ -+ reg1 &= 0x3f; -+ -+ switch (tone) { -+ case SEC_TONE_ON: -+ reg0 |= 0x4; -+ reg0 &= 0xbc; -+ break; -+ case SEC_TONE_OFF: -+ reg1 |= 0x80; -+ break; -+ default: -+ break; -+ } -+ m88rs2000_demod_write(state, 0xb2, reg1); -+ m88rs2000_demod_write(state, 0xb1, reg0); -+ m88rs2000_demod_write(state, 0x9a, 0xb0); -+ return 0; -+} -+ -+struct inittab { -+ u8 cmd; -+ u8 reg; -+ u8 val; -+}; -+ -+struct inittab m88rs2000_setup[] = { -+ {DEMOD_WRITE, 0x9a, 0x30}, -+ {DEMOD_WRITE, 0x00, 0x01}, -+ {WRITE_DELAY, 0x19, 0x00}, -+ {DEMOD_WRITE, 0x00, 0x00}, -+ {DEMOD_WRITE, 0x9a, 0xb0}, -+ {DEMOD_WRITE, 0x81, 0xc1}, -+ {TUNER_WRITE, 0x42, 0x73}, -+ {TUNER_WRITE, 0x05, 0x07}, -+ {TUNER_WRITE, 0x20, 0x27}, -+ {TUNER_WRITE, 0x07, 0x02}, -+ {TUNER_WRITE, 0x11, 0xff}, -+ {TUNER_WRITE, 0x60, 0xf9}, -+ {TUNER_WRITE, 0x08, 0x01}, -+ {TUNER_WRITE, 0x00, 0x41}, -+ {DEMOD_WRITE, 0x81, 0x81}, -+ {DEMOD_WRITE, 0x86, 0xc6}, -+ {DEMOD_WRITE, 0x9a, 0x30}, -+ {DEMOD_WRITE, 0xf0, 0x22}, -+ {DEMOD_WRITE, 0xf1, 0xbf}, -+ {DEMOD_WRITE, 0xb0, 0x45}, -+ {DEMOD_WRITE, 0xb2, 0x01}, /* set voltage pin always set 1*/ -+ {DEMOD_WRITE, 0x9a, 0xb0}, -+ {0xff, 0xaa, 0xff} -+}; -+ -+struct inittab m88rs2000_shutdown[] = { -+ {DEMOD_WRITE, 0x9a, 0x30}, -+ {DEMOD_WRITE, 0xb0, 0x00}, -+ {DEMOD_WRITE, 0xf1, 0x89}, -+ {DEMOD_WRITE, 0x00, 0x01}, -+ {DEMOD_WRITE, 0x9a, 0xb0}, -+ {TUNER_WRITE, 0x00, 0x40}, -+ {DEMOD_WRITE, 0x81, 0x81}, -+ {0xff, 0xaa, 0xff} -+}; -+ -+struct inittab tuner_reset[] = { -+ {TUNER_WRITE, 0x42, 0x73}, -+ {TUNER_WRITE, 0x05, 0x07}, -+ {TUNER_WRITE, 0x20, 0x27}, -+ {TUNER_WRITE, 0x07, 0x02}, -+ {TUNER_WRITE, 0x11, 0xff}, -+ {TUNER_WRITE, 0x60, 0xf9}, -+ {TUNER_WRITE, 0x08, 0x01}, -+ {TUNER_WRITE, 0x00, 0x41}, -+ {0xff, 0xaa, 0xff} -+}; -+ -+struct inittab fe_reset[] = { -+ {DEMOD_WRITE, 0x00, 0x01}, -+ {DEMOD_WRITE, 0xf1, 0xbf}, -+ {DEMOD_WRITE, 0x00, 0x01}, -+ {DEMOD_WRITE, 0x20, 0x81}, -+ {DEMOD_WRITE, 0x21, 0x80}, -+ {DEMOD_WRITE, 0x10, 0x33}, -+ {DEMOD_WRITE, 0x11, 0x44}, -+ {DEMOD_WRITE, 0x12, 0x07}, -+ {DEMOD_WRITE, 0x18, 0x20}, -+ {DEMOD_WRITE, 0x28, 0x04}, -+ {DEMOD_WRITE, 0x29, 0x8e}, -+ {DEMOD_WRITE, 0x3b, 0xff}, -+ {DEMOD_WRITE, 0x32, 0x10}, -+ {DEMOD_WRITE, 0x33, 0x02}, -+ {DEMOD_WRITE, 0x34, 0x30}, -+ {DEMOD_WRITE, 0x35, 0xff}, -+ {DEMOD_WRITE, 0x38, 0x50}, -+ {DEMOD_WRITE, 0x39, 0x68}, -+ {DEMOD_WRITE, 0x3c, 0x7f}, -+ {DEMOD_WRITE, 0x3d, 0x0f}, -+ {DEMOD_WRITE, 0x45, 0x20}, -+ {DEMOD_WRITE, 0x46, 0x24}, -+ {DEMOD_WRITE, 0x47, 0x7c}, -+ {DEMOD_WRITE, 0x48, 0x16}, -+ {DEMOD_WRITE, 0x49, 0x04}, -+ {DEMOD_WRITE, 0x4a, 0x01}, -+ {DEMOD_WRITE, 0x4b, 0x78}, -+ {DEMOD_WRITE, 0X4d, 0xd2}, -+ {DEMOD_WRITE, 0x4e, 0x6d}, -+ {DEMOD_WRITE, 0x50, 0x30}, -+ {DEMOD_WRITE, 0x51, 0x30}, -+ {DEMOD_WRITE, 0x54, 0x7b}, -+ {DEMOD_WRITE, 0x56, 0x09}, -+ {DEMOD_WRITE, 0x58, 0x59}, -+ {DEMOD_WRITE, 0x59, 0x37}, -+ {DEMOD_WRITE, 0x63, 0xfa}, -+ {0xff, 0xaa, 0xff} -+}; -+ -+struct inittab fe_trigger[] = { -+ {DEMOD_WRITE, 0x97, 0x04}, -+ {DEMOD_WRITE, 0x99, 0x77}, -+ {DEMOD_WRITE, 0x9b, 0x64}, -+ {DEMOD_WRITE, 0x9e, 0x00}, -+ {DEMOD_WRITE, 0x9f, 0xf8}, -+ {DEMOD_WRITE, 0xa0, 0x20}, -+ {DEMOD_WRITE, 0xa1, 0xe0}, -+ {DEMOD_WRITE, 0xa3, 0x38}, -+ {DEMOD_WRITE, 0x98, 0xff}, -+ {DEMOD_WRITE, 0xc0, 0x0f}, -+ {DEMOD_WRITE, 0x89, 0x01}, -+ {DEMOD_WRITE, 0x00, 0x00}, -+ {WRITE_DELAY, 0x0a, 0x00}, -+ {DEMOD_WRITE, 0x00, 0x01}, -+ {DEMOD_WRITE, 0x00, 0x00}, -+ {DEMOD_WRITE, 0x9a, 0xb0}, -+ {0xff, 0xaa, 0xff} -+}; -+ -+static int m88rs2000_tab_set(struct m88rs2000_state *state, -+ struct inittab *tab) -+{ -+ int ret = 0; -+ u8 i; -+ if (tab == NULL) -+ return -EINVAL; -+ -+ for (i = 0; i < 255; i++) { -+ switch (tab[i].cmd) { -+ case 0x01: -+ ret = m88rs2000_demod_write(state, tab[i].reg, -+ tab[i].val); -+ break; -+ case 0x02: -+ ret = m88rs2000_tuner_write(state, tab[i].reg, -+ tab[i].val); -+ break; -+ case 0x10: -+ if (tab[i].reg > 0) -+ mdelay(tab[i].reg); -+ break; -+ case 0xff: -+ if (tab[i].reg == 0xaa && tab[i].val == 0xff) -+ return 0; -+ case 0x00: -+ break; -+ default: -+ return -EINVAL; -+ } -+ if (ret < 0) -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) -+{ -+ deb_info("%s: %s\n", __func__, -+ volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : -+ volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); -+ -+ return 0; -+} -+ -+static int m88rs2000_startup(struct m88rs2000_state *state) -+{ -+ int ret = 0; -+ u8 reg; -+ -+ reg = m88rs2000_tuner_read(state, 0x00); -+ if ((reg & 0x40) == 0) -+ ret = -ENODEV; -+ -+ return ret; -+} -+ -+static int m88rs2000_init(struct dvb_frontend *fe) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ int ret; -+ -+ deb_info("m88rs2000: init chip\n"); -+ /* Setup frontend from shutdown/cold */ -+ ret = m88rs2000_tab_set(state, m88rs2000_setup); -+ -+ return ret; -+} -+ -+static int m88rs2000_sleep(struct dvb_frontend *fe) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ int ret; -+ /* Shutdown the frondend */ -+ ret = m88rs2000_tab_set(state, m88rs2000_shutdown); -+ return ret; -+} -+ -+static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ u8 reg = m88rs2000_demod_read(state, 0x8c); -+ -+ *status = 0; -+ -+ if ((reg & 0x7) == 0x7) { -+ *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI -+ | FE_HAS_LOCK; -+ if (state->config->set_ts_params) -+ state->config->set_ts_params(fe, CALL_IS_READ); -+ } -+ return 0; -+} -+ -+/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */ -+ -+static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber) -+{ -+ deb_info("m88rs2000_read_ber %d\n", *ber); -+ *ber = 0; -+ return 0; -+} -+ -+static int m88rs2000_read_signal_strength(struct dvb_frontend *fe, -+ u16 *strength) -+{ -+ *strength = 0; -+ return 0; -+} -+ -+static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) -+{ -+ deb_info("m88rs2000_read_snr %d\n", *snr); -+ *snr = 0; -+ return 0; -+} -+ -+static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -+{ -+ deb_info("m88rs2000_read_ber %d\n", *ucblocks); -+ *ucblocks = 0; -+ return 0; -+} -+ -+static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset) -+{ -+ int ret; -+ ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset); -+ ret |= m88rs2000_tuner_write(state, 0x51, 0x1f); -+ ret |= m88rs2000_tuner_write(state, 0x50, offset); -+ ret |= m88rs2000_tuner_write(state, 0x50, 0x00); -+ msleep(20); -+ return ret; -+} -+ -+static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ int reg; -+ reg = m88rs2000_tuner_read(state, 0x3d); -+ reg &= 0x7f; -+ if (reg < 0x16) -+ reg = 0xa1; -+ else if (reg == 0x16) -+ reg = 0x99; -+ else -+ reg = 0xf9; -+ -+ m88rs2000_tuner_write(state, 0x60, reg); -+ reg = m88rs2000_tuner_gate_ctrl(state, 0x08); -+ -+ if (fe->ops.i2c_gate_ctrl) -+ fe->ops.i2c_gate_ctrl(fe, 0); -+ return reg; -+} -+ -+static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset) -+{ -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ int ret; -+ u32 frequency = c->frequency; -+ s32 offset_khz; -+ s32 tmp; -+ u32 symbol_rate = (c->symbol_rate / 1000); -+ u32 f3db, gdiv28; -+ u16 value, ndiv, lpf_coeff; -+ u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf; -+ u8 lo = 0x01, div4 = 0x0; -+ -+ /* Reset Tuner */ -+ ret = m88rs2000_tab_set(state, tuner_reset); -+ -+ /* Calculate frequency divider */ -+ if (frequency < 1060000) { -+ lo |= 0x10; -+ div4 = 0x1; -+ ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ; -+ } else -+ ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ; -+ ndiv = ndiv + ndiv % 2; -+ ndiv = ndiv - 1024; -+ -+ ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo); -+ -+ /* Set frequency divider */ -+ ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf); -+ ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff); -+ -+ ret |= m88rs2000_tuner_write(state, 0x03, 0x06); -+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x10); -+ if (ret < 0) -+ return -ENODEV; -+ -+ /* Tuner Frequency Range */ -+ ret = m88rs2000_tuner_write(state, 0x10, lo); -+ -+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x08); -+ -+ /* Tuner RF */ -+ ret |= m88rs2000_set_tuner_rf(fe); -+ -+ gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000; -+ ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff); -+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x04); -+ if (ret < 0) -+ return -ENODEV; -+ -+ value = m88rs2000_tuner_read(state, 0x26); -+ -+ f3db = (symbol_rate * 135) / 200 + 2000; -+ f3db += FREQ_OFFSET_LOW_SYM_RATE; -+ if (f3db < 7000) -+ f3db = 7000; -+ if (f3db > 40000) -+ f3db = 40000; -+ -+ gdiv28 = gdiv28 * 207 / (value * 2 + 151); -+ mlpf_max = gdiv28 * 135 / 100; -+ mlpf_min = gdiv28 * 78 / 100; -+ if (mlpf_max > 63) -+ mlpf_max = 63; -+ -+ lpf_coeff = 2766; -+ -+ nlpf = (f3db * gdiv28 * 2 / lpf_coeff / -+ (FE_CRYSTAL_KHZ / 1000) + 1) / 2; -+ if (nlpf > 23) -+ nlpf = 23; -+ if (nlpf < 1) -+ nlpf = 1; -+ -+ lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000) -+ * lpf_coeff * 2 / f3db + 1) / 2; -+ -+ if (lpf_mxdiv < mlpf_min) { -+ nlpf++; -+ lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000) -+ * lpf_coeff * 2 / f3db + 1) / 2; -+ } -+ -+ if (lpf_mxdiv > mlpf_max) -+ lpf_mxdiv = mlpf_max; -+ -+ ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv); -+ ret |= m88rs2000_tuner_write(state, 0x06, nlpf); -+ -+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x04); -+ -+ ret |= m88rs2000_tuner_gate_ctrl(state, 0x01); -+ -+ msleep(80); -+ /* calculate offset assuming 96000kHz*/ -+ offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ -+ / 14 / (div4 + 1) / 2; -+ -+ offset_khz -= frequency; -+ -+ tmp = offset_khz; -+ tmp *= 65536; -+ -+ tmp = (2 * tmp + 96000) / (2 * 96000); -+ if (tmp < 0) -+ tmp += 65536; -+ -+ *offset = tmp & 0xffff; -+ -+ if (fe->ops.i2c_gate_ctrl) -+ fe->ops.i2c_gate_ctrl(fe, 0); -+ -+ return (ret < 0) ? -EINVAL : 0; -+} -+ -+static int m88rs2000_set_fec(struct m88rs2000_state *state, -+ fe_code_rate_t fec) -+{ -+ int ret; -+ u16 fec_set; -+ switch (fec) { -+ /* This is not confirmed kept for reference */ -+/* case FEC_1_2: -+ fec_set = 0x88; -+ break; -+ case FEC_2_3: -+ fec_set = 0x68; -+ break; -+ case FEC_3_4: -+ fec_set = 0x48; -+ break; -+ case FEC_5_6: -+ fec_set = 0x28; -+ break; -+ case FEC_7_8: -+ fec_set = 0x18; -+ break; */ -+ case FEC_AUTO: -+ default: -+ fec_set = 0x08; -+ } -+ ret = m88rs2000_demod_write(state, 0x76, fec_set); -+ -+ return 0; -+} -+ -+ -+static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state) -+{ -+ u8 reg; -+ m88rs2000_demod_write(state, 0x9a, 0x30); -+ reg = m88rs2000_demod_read(state, 0x76); -+ m88rs2000_demod_write(state, 0x9a, 0xb0); -+ -+ switch (reg) { -+ case 0x88: -+ return FEC_1_2; -+ case 0x68: -+ return FEC_2_3; -+ case 0x48: -+ return FEC_3_4; -+ case 0x28: -+ return FEC_5_6; -+ case 0x18: -+ return FEC_7_8; -+ case 0x08: -+ default: -+ break; -+ } -+ -+ return FEC_AUTO; -+} -+ -+static int m88rs2000_set_frontend(struct dvb_frontend *fe) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ fe_status_t status; -+ int i, ret; -+ u16 offset = 0; -+ u8 reg; -+ -+ state->no_lock_count = 0; -+ -+ if (c->delivery_system != SYS_DVBS) { -+ deb_info("%s: unsupported delivery " -+ "system selected (%d)\n", -+ __func__, c->delivery_system); -+ return -EOPNOTSUPP; -+ } -+ -+ /* Set Tuner */ -+ ret = m88rs2000_set_tuner(fe, &offset); -+ if (ret < 0) -+ return -ENODEV; -+ -+ ret = m88rs2000_demod_write(state, 0x9a, 0x30); -+ /* Unknown usually 0xc6 sometimes 0xc1 */ -+ reg = m88rs2000_demod_read(state, 0x86); -+ ret |= m88rs2000_demod_write(state, 0x86, reg); -+ /* Offset lower nibble always 0 */ -+ ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8)); -+ ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0); -+ -+ -+ /* Reset Demod */ -+ ret = m88rs2000_tab_set(state, fe_reset); -+ if (ret < 0) -+ return -ENODEV; -+ -+ /* Unknown */ -+ reg = m88rs2000_demod_read(state, 0x70); -+ ret = m88rs2000_demod_write(state, 0x70, reg); -+ -+ /* Set FEC */ -+ ret |= m88rs2000_set_fec(state, c->fec_inner); -+ ret |= m88rs2000_demod_write(state, 0x85, 0x1); -+ ret |= m88rs2000_demod_write(state, 0x8a, 0xbf); -+ ret |= m88rs2000_demod_write(state, 0x8d, 0x1e); -+ ret |= m88rs2000_demod_write(state, 0x90, 0xf1); -+ ret |= m88rs2000_demod_write(state, 0x91, 0x08); -+ -+ if (ret < 0) -+ return -ENODEV; -+ -+ /* Set Symbol Rate */ -+ ret = m88rs2000_set_symbolrate(fe, c->symbol_rate); -+ if (ret < 0) -+ return -ENODEV; -+ -+ /* Set up Demod */ -+ ret = m88rs2000_tab_set(state, fe_trigger); -+ if (ret < 0) -+ return -ENODEV; -+ -+ for (i = 0; i < 25; i++) { -+ u8 reg = m88rs2000_demod_read(state, 0x8c); -+ if ((reg & 0x7) == 0x7) { -+ status = FE_HAS_LOCK; -+ break; -+ } -+ state->no_lock_count++; -+ if (state->no_lock_count > 15) { -+ reg = m88rs2000_demod_read(state, 0x70); -+ reg ^= 0x4; -+ m88rs2000_demod_write(state, 0x70, reg); -+ state->no_lock_count = 0; -+ } -+ if (state->no_lock_count == 20) -+ m88rs2000_set_tuner_rf(fe); -+ msleep(20); -+ } -+ -+ if (status & FE_HAS_LOCK) { -+ state->fec_inner = m88rs2000_get_fec(state); -+ /* Uknown suspect SNR level */ -+ reg = m88rs2000_demod_read(state, 0x65); -+ } -+ -+ state->tuner_frequency = c->frequency; -+ state->symbol_rate = c->symbol_rate; -+ return 0; -+} -+ -+static int m88rs2000_get_frontend(struct dvb_frontend *fe) -+{ -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ c->fec_inner = state->fec_inner; -+ c->frequency = state->tuner_frequency; -+ c->symbol_rate = state->symbol_rate; -+ return 0; -+} -+ -+static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ -+ if (enable) -+ m88rs2000_demod_write(state, 0x81, 0x84); -+ else -+ m88rs2000_demod_write(state, 0x81, 0x81); -+ udelay(10); -+ return 0; -+} -+ -+static void m88rs2000_release(struct dvb_frontend *fe) -+{ -+ struct m88rs2000_state *state = fe->demodulator_priv; -+ kfree(state); -+} -+ -+static struct dvb_frontend_ops m88rs2000_ops = { -+ .delsys = { SYS_DVBS }, -+ .info = { -+ .name = "M88RS2000 DVB-S", -+ .frequency_min = 950000, -+ .frequency_max = 2150000, -+ .frequency_stepsize = 1000, /* kHz for QPSK frontends */ -+ .frequency_tolerance = 5000, -+ .symbol_rate_min = 1000000, -+ .symbol_rate_max = 45000000, -+ .symbol_rate_tolerance = 500, /* ppm */ -+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | -+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | -+ FE_CAN_QPSK | -+ FE_CAN_FEC_AUTO -+ }, -+ -+ .release = m88rs2000_release, -+ .init = m88rs2000_init, -+ .sleep = m88rs2000_sleep, -+ .write = m88rs2000_write, -+ .i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl, -+ .read_status = m88rs2000_read_status, -+ .read_ber = m88rs2000_read_ber, -+ .read_signal_strength = m88rs2000_read_signal_strength, -+ .read_snr = m88rs2000_read_snr, -+ .read_ucblocks = m88rs2000_read_ucblocks, -+ .diseqc_send_master_cmd = m88rs2000_send_diseqc_msg, -+ .diseqc_send_burst = m88rs2000_send_diseqc_burst, -+ .set_tone = m88rs2000_set_tone, -+ .set_voltage = m88rs2000_set_voltage, -+ -+ .set_frontend = m88rs2000_set_frontend, -+ .get_frontend = m88rs2000_get_frontend, -+}; -+ -+struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config, -+ struct i2c_adapter *i2c) -+{ -+ struct m88rs2000_state *state = NULL; -+ -+ /* allocate memory for the internal state */ -+ state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL); -+ if (state == NULL) -+ goto error; -+ -+ /* setup the state */ -+ state->config = config; -+ state->i2c = i2c; -+ state->tuner_frequency = 0; -+ state->symbol_rate = 0; -+ state->fec_inner = 0; -+ -+ if (m88rs2000_startup(state) < 0) -+ goto error; -+ -+ /* create dvb_frontend */ -+ memcpy(&state->frontend.ops, &m88rs2000_ops, -+ sizeof(struct dvb_frontend_ops)); -+ state->frontend.demodulator_priv = state; -+ return &state->frontend; -+ -+error: -+ kfree(state); -+ -+ return NULL; -+} -+EXPORT_SYMBOL(m88rs2000_attach); -+ -+MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver"); -+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION("1.13"); -+ -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/m88rs2000.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/m88rs2000.h -@@ -0,0 +1,66 @@ -+/* -+ Driver for M88RS2000 demodulator -+ -+ 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 M88RS2000_H -+#define M88RS2000_H -+ -+#include -+#include "dvb_frontend.h" -+ -+struct m88rs2000_config { -+ /* Demodulator i2c address */ -+ u8 demod_addr; -+ /* Tuner address */ -+ u8 tuner_addr; -+ -+ u8 *inittab; -+ -+ /* minimum delay before retuning */ -+ int min_delay_ms; -+ -+ int (*set_ts_params)(struct dvb_frontend *, int); -+}; -+ -+enum { -+ CALL_IS_SET_FRONTEND = 0x0, -+ CALL_IS_READ, -+}; -+ -+#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \ -+ defined(MODULE)) -+extern struct dvb_frontend *m88rs2000_attach( -+ const struct m88rs2000_config *config, struct i2c_adapter *i2c); -+#else -+static inline struct dvb_frontend *m88rs2000_attach( -+ const struct m88rs2000_config *config, struct i2c_adapter *i2c) -+{ -+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -+ return NULL; -+} -+#endif /* CONFIG_DVB_M88RS2000 */ -+ -+#define FE_CRYSTAL_KHZ 27000 -+#define FREQ_OFFSET_LOW_SYM_RATE 3000 -+ -+enum { -+ DEMOD_WRITE = 0x1, -+ TUNER_WRITE, -+ WRITE_DELAY = 0x10, -+}; -+#endif /* M88RS2000_H */ -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/lmedm04.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/lmedm04.h -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/lmedm04.h -@@ -41,6 +41,7 @@ - #define LME_ST_ON_W {0x06, 0x00} - #define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0} - #define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c} -+#define LME_ALL_PIDS {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81} - - /* LNB Voltage - * 07 XX XX -Index: linux-3.3.x86_64/drivers/media/video/adv7183.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/adv7183.c -@@ -0,0 +1,699 @@ -+/* -+ * adv7183.c Analog Devices ADV7183 video decoder driver -+ * -+ * Copyright (c) 2011 Analog Devices Inc. -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "adv7183_regs.h" -+ -+struct adv7183 { -+ struct v4l2_subdev sd; -+ struct v4l2_ctrl_handler hdl; -+ -+ v4l2_std_id std; /* Current set standard */ -+ u32 input; -+ u32 output; -+ unsigned reset_pin; -+ unsigned oe_pin; -+ struct v4l2_mbus_framefmt fmt; -+}; -+ -+/* EXAMPLES USING 27 MHz CLOCK -+ * Mode 1 CVBS Input (Composite Video on AIN5) -+ * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8. -+ */ -+static const unsigned char adv7183_init_regs[] = { -+ ADV7183_IN_CTRL, 0x04, /* CVBS input on AIN5 */ -+ ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */ -+ ADV7183_SHAP_FILT_CTRL, 0x41, /* Set CSFM to SH1 */ -+ ADV7183_ADC_CTRL, 0x16, /* Power down ADC 1 and ADC 2 */ -+ ADV7183_CTI_DNR_CTRL_4, 0x04, /* Set DNR threshold to 4 for flat response */ -+ /* ADI recommended programming sequence */ -+ ADV7183_ADI_CTRL, 0x80, -+ ADV7183_CTI_DNR_CTRL_4, 0x20, -+ 0x52, 0x18, -+ 0x58, 0xED, -+ 0x77, 0xC5, -+ 0x7C, 0x93, -+ 0x7D, 0x00, -+ 0xD0, 0x48, -+ 0xD5, 0xA0, -+ 0xD7, 0xEA, -+ ADV7183_SD_SATURATION_CR, 0x3E, -+ ADV7183_PAL_V_END, 0x3E, -+ ADV7183_PAL_F_TOGGLE, 0x0F, -+ ADV7183_ADI_CTRL, 0x00, -+}; -+ -+static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct adv7183, sd); -+} -+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -+{ -+ return &container_of(ctrl->handler, struct adv7183, hdl)->sd; -+} -+ -+static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ return i2c_smbus_read_byte_data(client, reg); -+} -+ -+static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg, -+ unsigned char value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ return i2c_smbus_write_byte_data(client, reg, value); -+} -+ -+static int adv7183_writeregs(struct v4l2_subdev *sd, -+ const unsigned char *regs, unsigned int num) -+{ -+ unsigned char reg, data; -+ unsigned int cnt = 0; -+ -+ if (num & 0x1) { -+ v4l2_err(sd, "invalid regs array\n"); -+ return -1; -+ } -+ -+ while (cnt < num) { -+ reg = *regs++; -+ data = *regs++; -+ cnt += 2; -+ -+ adv7183_write(sd, reg, data); -+ } -+ return 0; -+} -+ -+static int adv7183_log_status(struct v4l2_subdev *sd) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ -+ v4l2_info(sd, "adv7183: Input control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_IN_CTRL)); -+ v4l2_info(sd, "adv7183: Video selection = 0x%02x\n", -+ adv7183_read(sd, ADV7183_VD_SEL)); -+ v4l2_info(sd, "adv7183: Output control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_OUT_CTRL)); -+ v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_EXT_OUT_CTRL)); -+ v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n", -+ adv7183_read(sd, ADV7183_AUTO_DET_EN)); -+ v4l2_info(sd, "adv7183: Contrast = 0x%02x\n", -+ adv7183_read(sd, ADV7183_CONTRAST)); -+ v4l2_info(sd, "adv7183: Brightness = 0x%02x\n", -+ adv7183_read(sd, ADV7183_BRIGHTNESS)); -+ v4l2_info(sd, "adv7183: Hue = 0x%02x\n", -+ adv7183_read(sd, ADV7183_HUE)); -+ v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n", -+ adv7183_read(sd, ADV7183_DEF_Y)); -+ v4l2_info(sd, "adv7183: Default value C = 0x%02x\n", -+ adv7183_read(sd, ADV7183_DEF_C)); -+ v4l2_info(sd, "adv7183: ADI control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_ADI_CTRL)); -+ v4l2_info(sd, "adv7183: Power Management = 0x%02x\n", -+ adv7183_read(sd, ADV7183_POW_MANAGE)); -+ v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", -+ adv7183_read(sd, ADV7183_STATUS_1), -+ adv7183_read(sd, ADV7183_STATUS_2), -+ adv7183_read(sd, ADV7183_STATUS_3)); -+ v4l2_info(sd, "adv7183: Ident = 0x%02x\n", -+ adv7183_read(sd, ADV7183_IDENT)); -+ v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL)); -+ v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n", -+ adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1)); -+ v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n", -+ adv7183_read(sd, ADV7183_SHAP_FILT_CTRL), -+ adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2)); -+ v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_COMB_FILT_CTRL)); -+ v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n", -+ adv7183_read(sd, ADV7183_ADI_CTRL_2)); -+ v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_PIX_DELAY_CTRL)); -+ v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_MISC_GAIN_CTRL)); -+ v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_AGC_MODE_CTRL)); -+ v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n", -+ adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1), -+ adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2)); -+ v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n", -+ adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1), -+ adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2)); -+ v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", -+ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1), -+ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2), -+ adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3)); -+ v4l2_info(sd, "adv7183: Hsync positon control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", -+ adv7183_read(sd, ADV7183_HS_POS_CTRL_1), -+ adv7183_read(sd, ADV7183_HS_POS_CTRL_2), -+ adv7183_read(sd, ADV7183_HS_POS_CTRL_3)); -+ v4l2_info(sd, "adv7183: Polarity = 0x%02x\n", -+ adv7183_read(sd, ADV7183_POLARITY)); -+ v4l2_info(sd, "adv7183: ADC control = 0x%02x\n", -+ adv7183_read(sd, ADV7183_ADC_CTRL)); -+ v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n", -+ adv7183_read(sd, ADV7183_SD_OFFSET_CB), -+ adv7183_read(sd, ADV7183_SD_OFFSET_CR)); -+ v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n", -+ adv7183_read(sd, ADV7183_SD_SATURATION_CB), -+ adv7183_read(sd, ADV7183_SD_SATURATION_CR)); -+ v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n", -+ adv7183_read(sd, ADV7183_DRIVE_STR)); -+ v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name); -+ return 0; -+} -+ -+static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ -+ *std = decoder->std; -+ return 0; -+} -+ -+static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ int reg; -+ -+ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF; -+ if (std == V4L2_STD_PAL_60) -+ reg |= 0x60; -+ else if (std == V4L2_STD_NTSC_443) -+ reg |= 0x70; -+ else if (std == V4L2_STD_PAL_N) -+ reg |= 0x90; -+ else if (std == V4L2_STD_PAL_M) -+ reg |= 0xA0; -+ else if (std == V4L2_STD_PAL_Nc) -+ reg |= 0xC0; -+ else if (std & V4L2_STD_PAL) -+ reg |= 0x80; -+ else if (std & V4L2_STD_NTSC) -+ reg |= 0x50; -+ else if (std & V4L2_STD_SECAM) -+ reg |= 0xE0; -+ else -+ return -EINVAL; -+ adv7183_write(sd, ADV7183_IN_CTRL, reg); -+ -+ decoder->std = std; -+ -+ return 0; -+} -+ -+static int adv7183_reset(struct v4l2_subdev *sd, u32 val) -+{ -+ int reg; -+ -+ reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80; -+ adv7183_write(sd, ADV7183_POW_MANAGE, reg); -+ /* wait 5ms before any further i2c writes are performed */ -+ usleep_range(5000, 10000); -+ return 0; -+} -+ -+static int adv7183_s_routing(struct v4l2_subdev *sd, -+ u32 input, u32 output, u32 config) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ int reg; -+ -+ if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT)) -+ return -EINVAL; -+ -+ if (input != decoder->input) { -+ decoder->input = input; -+ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0; -+ switch (input) { -+ case ADV7183_COMPOSITE1: -+ reg |= 0x1; -+ break; -+ case ADV7183_COMPOSITE2: -+ reg |= 0x2; -+ break; -+ case ADV7183_COMPOSITE3: -+ reg |= 0x3; -+ break; -+ case ADV7183_COMPOSITE4: -+ reg |= 0x4; -+ break; -+ case ADV7183_COMPOSITE5: -+ reg |= 0x5; -+ break; -+ case ADV7183_COMPOSITE6: -+ reg |= 0xB; -+ break; -+ case ADV7183_COMPOSITE7: -+ reg |= 0xC; -+ break; -+ case ADV7183_COMPOSITE8: -+ reg |= 0xD; -+ break; -+ case ADV7183_COMPOSITE9: -+ reg |= 0xE; -+ break; -+ case ADV7183_COMPOSITE10: -+ reg |= 0xF; -+ break; -+ case ADV7183_SVIDEO0: -+ reg |= 0x6; -+ break; -+ case ADV7183_SVIDEO1: -+ reg |= 0x7; -+ break; -+ case ADV7183_SVIDEO2: -+ reg |= 0x8; -+ break; -+ case ADV7183_COMPONENT0: -+ reg |= 0x9; -+ break; -+ case ADV7183_COMPONENT1: -+ reg |= 0xA; -+ break; -+ default: -+ break; -+ } -+ adv7183_write(sd, ADV7183_IN_CTRL, reg); -+ } -+ -+ if (output != decoder->output) { -+ decoder->output = output; -+ reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0; -+ switch (output) { -+ case ADV7183_16BIT_OUT: -+ reg |= 0x9; -+ break; -+ default: -+ reg |= 0xC; -+ break; -+ } -+ adv7183_write(sd, ADV7183_OUT_CTRL, reg); -+ } -+ -+ return 0; -+} -+ -+static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct v4l2_subdev *sd = to_sd(ctrl); -+ int val = ctrl->val; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_BRIGHTNESS: -+ if (val < 0) -+ val = 127 - val; -+ adv7183_write(sd, ADV7183_BRIGHTNESS, val); -+ break; -+ case V4L2_CID_CONTRAST: -+ adv7183_write(sd, ADV7183_CONTRAST, val); -+ break; -+ case V4L2_CID_SATURATION: -+ adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8); -+ adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF)); -+ break; -+ case V4L2_CID_HUE: -+ adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8); -+ adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF)); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ int reg; -+ -+ /* enable autodetection block */ -+ reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF; -+ adv7183_write(sd, ADV7183_IN_CTRL, reg); -+ -+ /* wait autodetection switch */ -+ mdelay(10); -+ -+ /* get autodetection result */ -+ reg = adv7183_read(sd, ADV7183_STATUS_1); -+ switch ((reg >> 0x4) & 0x7) { -+ case 0: -+ *std = V4L2_STD_NTSC; -+ break; -+ case 1: -+ *std = V4L2_STD_NTSC_443; -+ break; -+ case 2: -+ *std = V4L2_STD_PAL_M; -+ break; -+ case 3: -+ *std = V4L2_STD_PAL_60; -+ break; -+ case 4: -+ *std = V4L2_STD_PAL; -+ break; -+ case 5: -+ *std = V4L2_STD_SECAM; -+ break; -+ case 6: -+ *std = V4L2_STD_PAL_Nc; -+ break; -+ case 7: -+ *std = V4L2_STD_SECAM; -+ break; -+ default: -+ *std = V4L2_STD_UNKNOWN; -+ break; -+ } -+ -+ /* after std detection, write back user set std */ -+ adv7183_s_std(sd, decoder->std); -+ return 0; -+} -+ -+static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status) -+{ -+ int reg; -+ -+ *status = V4L2_IN_ST_NO_SIGNAL; -+ reg = adv7183_read(sd, ADV7183_STATUS_1); -+ if (reg < 0) -+ return reg; -+ if (reg & 0x1) -+ *status = 0; -+ return 0; -+} -+ -+static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, -+ enum v4l2_mbus_pixelcode *code) -+{ -+ if (index > 0) -+ return -EINVAL; -+ -+ *code = V4L2_MBUS_FMT_UYVY8_2X8; -+ return 0; -+} -+ -+static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *fmt) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ -+ fmt->code = V4L2_MBUS_FMT_UYVY8_2X8; -+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; -+ if (decoder->std & V4L2_STD_525_60) { -+ fmt->field = V4L2_FIELD_SEQ_TB; -+ fmt->width = 720; -+ fmt->height = 480; -+ } else { -+ fmt->field = V4L2_FIELD_SEQ_BT; -+ fmt->width = 720; -+ fmt->height = 576; -+ } -+ return 0; -+} -+ -+static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *fmt) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ -+ adv7183_try_mbus_fmt(sd, fmt); -+ decoder->fmt = *fmt; -+ return 0; -+} -+ -+static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *fmt) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ -+ *fmt = decoder->fmt; -+ return 0; -+} -+ -+static int adv7183_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct adv7183 *decoder = to_adv7183(sd); -+ -+ if (enable) -+ gpio_direction_output(decoder->oe_pin, 0); -+ else -+ gpio_direction_output(decoder->oe_pin, 1); -+ udelay(1); -+ return 0; -+} -+ -+static int adv7183_g_chip_ident(struct v4l2_subdev *sd, -+ struct v4l2_dbg_chip_ident *chip) -+{ -+ int rev; -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ /* 0x11 for adv7183, 0x13 for adv7183b */ -+ rev = adv7183_read(sd, ADV7183_IDENT); -+ -+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev); -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ reg->val = adv7183_read(sd, reg->reg & 0xff); -+ reg->size = 1; -+ return 0; -+} -+ -+static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff); -+ return 0; -+} -+#endif -+ -+static const struct v4l2_ctrl_ops adv7183_ctrl_ops = { -+ .s_ctrl = adv7183_s_ctrl, -+}; -+ -+static const struct v4l2_subdev_core_ops adv7183_core_ops = { -+ .log_status = adv7183_log_status, -+ .g_std = adv7183_g_std, -+ .s_std = adv7183_s_std, -+ .reset = adv7183_reset, -+ .g_chip_ident = adv7183_g_chip_ident, -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = adv7183_g_register, -+ .s_register = adv7183_s_register, -+#endif -+}; -+ -+static const struct v4l2_subdev_video_ops adv7183_video_ops = { -+ .s_routing = adv7183_s_routing, -+ .querystd = adv7183_querystd, -+ .g_input_status = adv7183_g_input_status, -+ .enum_mbus_fmt = adv7183_enum_mbus_fmt, -+ .try_mbus_fmt = adv7183_try_mbus_fmt, -+ .s_mbus_fmt = adv7183_s_mbus_fmt, -+ .g_mbus_fmt = adv7183_g_mbus_fmt, -+ .s_stream = adv7183_s_stream, -+}; -+ -+static const struct v4l2_subdev_ops adv7183_ops = { -+ .core = &adv7183_core_ops, -+ .video = &adv7183_video_ops, -+}; -+ -+static int adv7183_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct adv7183 *decoder; -+ struct v4l2_subdev *sd; -+ struct v4l2_ctrl_handler *hdl; -+ int ret; -+ struct v4l2_mbus_framefmt fmt; -+ const unsigned *pin_array; -+ -+ /* Check if the adapter supports the needed features */ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) -+ return -EIO; -+ -+ v4l_info(client, "chip found @ 0x%02x (%s)\n", -+ client->addr << 1, client->adapter->name); -+ -+ pin_array = client->dev.platform_data; -+ if (pin_array == NULL) -+ return -EINVAL; -+ -+ decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL); -+ if (decoder == NULL) -+ return -ENOMEM; -+ -+ decoder->reset_pin = pin_array[0]; -+ decoder->oe_pin = pin_array[1]; -+ -+ if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) { -+ v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin); -+ ret = -EBUSY; -+ goto err_free_decoder; -+ } -+ -+ if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) { -+ v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin); -+ ret = -EBUSY; -+ goto err_free_reset; -+ } -+ -+ sd = &decoder->sd; -+ v4l2_i2c_subdev_init(sd, client, &adv7183_ops); -+ -+ hdl = &decoder->hdl; -+ v4l2_ctrl_handler_init(hdl, 4); -+ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, -+ V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); -+ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, -+ V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80); -+ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, -+ V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080); -+ v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, -+ V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080); -+ /* hook the control handler into the driver */ -+ sd->ctrl_handler = hdl; -+ if (hdl->error) { -+ ret = hdl->error; -+ -+ v4l2_ctrl_handler_free(hdl); -+ goto err_free_oe; -+ } -+ -+ /* v4l2 doesn't support an autodetect standard, pick PAL as default */ -+ decoder->std = V4L2_STD_PAL; -+ decoder->input = ADV7183_COMPOSITE4; -+ decoder->output = ADV7183_8BIT_OUT; -+ -+ gpio_direction_output(decoder->oe_pin, 1); -+ /* reset chip */ -+ gpio_direction_output(decoder->reset_pin, 0); -+ /* reset pulse width at least 5ms */ -+ mdelay(10); -+ gpio_direction_output(decoder->reset_pin, 1); -+ /* wait 5ms before any further i2c writes are performed */ -+ mdelay(5); -+ -+ adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs)); -+ adv7183_s_std(sd, decoder->std); -+ fmt.width = 720; -+ fmt.height = 576; -+ adv7183_s_mbus_fmt(sd, &fmt); -+ -+ /* initialize the hardware to the default control values */ -+ ret = v4l2_ctrl_handler_setup(hdl); -+ if (ret) { -+ v4l2_ctrl_handler_free(hdl); -+ goto err_free_oe; -+ } -+ -+ return 0; -+err_free_oe: -+ gpio_free(decoder->oe_pin); -+err_free_reset: -+ gpio_free(decoder->reset_pin); -+err_free_decoder: -+ kfree(decoder); -+ return ret; -+} -+ -+static int adv7183_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct adv7183 *decoder = to_adv7183(sd); -+ -+ v4l2_device_unregister_subdev(sd); -+ v4l2_ctrl_handler_free(sd->ctrl_handler); -+ gpio_free(decoder->oe_pin); -+ gpio_free(decoder->reset_pin); -+ kfree(decoder); -+ return 0; -+} -+ -+static const struct i2c_device_id adv7183_id[] = { -+ {"adv7183", 0}, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(i2c, adv7183_id); -+ -+static struct i2c_driver adv7183_driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "adv7183", -+ }, -+ .probe = adv7183_probe, -+ .remove = __devexit_p(adv7183_remove), -+ .id_table = adv7183_id, -+}; -+ -+static __init int adv7183_init(void) -+{ -+ return i2c_add_driver(&adv7183_driver); -+} -+ -+static __exit void adv7183_exit(void) -+{ -+ i2c_del_driver(&adv7183_driver); -+} -+ -+module_init(adv7183_init); -+module_exit(adv7183_exit); -+ -+MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver"); -+MODULE_AUTHOR("Scott Jiang "); -+MODULE_LICENSE("GPL v2"); -Index: linux-3.3.x86_64/drivers/media/video/adv7183_regs.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/adv7183_regs.h -@@ -0,0 +1,107 @@ -+/* -+ * adv7183 - Analog Devices ADV7183 video decoder registers -+ * -+ * Copyright (c) 2011 Analog Devices Inc. -+ * -+ * 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. -+ * -+ * 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 _ADV7183_REGS_H_ -+#define _ADV7183_REGS_H_ -+ -+#define ADV7183_IN_CTRL 0x00 /* Input control */ -+#define ADV7183_VD_SEL 0x01 /* Video selection */ -+#define ADV7183_OUT_CTRL 0x03 /* Output control */ -+#define ADV7183_EXT_OUT_CTRL 0x04 /* Extended output control */ -+#define ADV7183_AUTO_DET_EN 0x07 /* Autodetect enable */ -+#define ADV7183_CONTRAST 0x08 /* Contrast */ -+#define ADV7183_BRIGHTNESS 0x0A /* Brightness */ -+#define ADV7183_HUE 0x0B /* Hue */ -+#define ADV7183_DEF_Y 0x0C /* Default value Y */ -+#define ADV7183_DEF_C 0x0D /* Default value C */ -+#define ADV7183_ADI_CTRL 0x0E /* ADI control */ -+#define ADV7183_POW_MANAGE 0x0F /* Power Management */ -+#define ADV7183_STATUS_1 0x10 /* Status 1 */ -+#define ADV7183_IDENT 0x11 /* Ident */ -+#define ADV7183_STATUS_2 0x12 /* Status 2 */ -+#define ADV7183_STATUS_3 0x13 /* Status 3 */ -+#define ADV7183_ANAL_CLAMP_CTRL 0x14 /* Analog clamp control */ -+#define ADV7183_DIGI_CLAMP_CTRL_1 0x15 /* Digital clamp control 1 */ -+#define ADV7183_SHAP_FILT_CTRL 0x17 /* Shaping filter control */ -+#define ADV7183_SHAP_FILT_CTRL_2 0x18 /* Shaping filter control 2 */ -+#define ADV7183_COMB_FILT_CTRL 0x19 /* Comb filter control */ -+#define ADV7183_ADI_CTRL_2 0x1D /* ADI control 2 */ -+#define ADV7183_PIX_DELAY_CTRL 0x27 /* Pixel delay control */ -+#define ADV7183_MISC_GAIN_CTRL 0x2B /* Misc gain control */ -+#define ADV7183_AGC_MODE_CTRL 0x2C /* AGC mode control */ -+#define ADV7183_CHRO_GAIN_CTRL_1 0x2D /* Chroma gain control 1 */ -+#define ADV7183_CHRO_GAIN_CTRL_2 0x2E /* Chroma gain control 2 */ -+#define ADV7183_LUMA_GAIN_CTRL_1 0x2F /* Luma gain control 1 */ -+#define ADV7183_LUMA_GAIN_CTRL_2 0x30 /* Luma gain control 2 */ -+#define ADV7183_VS_FIELD_CTRL_1 0x31 /* Vsync field control 1 */ -+#define ADV7183_VS_FIELD_CTRL_2 0x32 /* Vsync field control 2 */ -+#define ADV7183_VS_FIELD_CTRL_3 0x33 /* Vsync field control 3 */ -+#define ADV7183_HS_POS_CTRL_1 0x34 /* Hsync positon control 1 */ -+#define ADV7183_HS_POS_CTRL_2 0x35 /* Hsync positon control 2 */ -+#define ADV7183_HS_POS_CTRL_3 0x36 /* Hsync positon control 3 */ -+#define ADV7183_POLARITY 0x37 /* Polarity */ -+#define ADV7183_NTSC_COMB_CTRL 0x38 /* NTSC comb control */ -+#define ADV7183_PAL_COMB_CTRL 0x39 /* PAL comb control */ -+#define ADV7183_ADC_CTRL 0x3A /* ADC control */ -+#define ADV7183_MAN_WIN_CTRL 0x3D /* Manual window control */ -+#define ADV7183_RESAMPLE_CTRL 0x41 /* Resample control */ -+#define ADV7183_GEMSTAR_CTRL_1 0x48 /* Gemstar ctrl 1 */ -+#define ADV7183_GEMSTAR_CTRL_2 0x49 /* Gemstar ctrl 2 */ -+#define ADV7183_GEMSTAR_CTRL_3 0x4A /* Gemstar ctrl 3 */ -+#define ADV7183_GEMSTAR_CTRL_4 0x4B /* Gemstar ctrl 4 */ -+#define ADV7183_GEMSTAR_CTRL_5 0x4C /* Gemstar ctrl 5 */ -+#define ADV7183_CTI_DNR_CTRL_1 0x4D /* CTI DNR ctrl 1 */ -+#define ADV7183_CTI_DNR_CTRL_2 0x4E /* CTI DNR ctrl 2 */ -+#define ADV7183_CTI_DNR_CTRL_4 0x50 /* CTI DNR ctrl 4 */ -+#define ADV7183_LOCK_CNT 0x51 /* Lock count */ -+#define ADV7183_FREE_LINE_LEN 0x8F /* Free-Run line length 1 */ -+#define ADV7183_VBI_INFO 0x90 /* VBI info */ -+#define ADV7183_WSS_1 0x91 /* WSS 1 */ -+#define ADV7183_WSS_2 0x92 /* WSS 2 */ -+#define ADV7183_EDTV_1 0x93 /* EDTV 1 */ -+#define ADV7183_EDTV_2 0x94 /* EDTV 2 */ -+#define ADV7183_EDTV_3 0x95 /* EDTV 3 */ -+#define ADV7183_CGMS_1 0x96 /* CGMS 1 */ -+#define ADV7183_CGMS_2 0x97 /* CGMS 2 */ -+#define ADV7183_CGMS_3 0x98 /* CGMS 3 */ -+#define ADV7183_CCAP_1 0x99 /* CCAP 1 */ -+#define ADV7183_CCAP_2 0x9A /* CCAP 2 */ -+#define ADV7183_LETTERBOX_1 0x9B /* Letterbox 1 */ -+#define ADV7183_LETTERBOX_2 0x9C /* Letterbox 2 */ -+#define ADV7183_LETTERBOX_3 0x9D /* Letterbox 3 */ -+#define ADV7183_CRC_EN 0xB2 /* CRC enable */ -+#define ADV7183_ADC_SWITCH_1 0xC3 /* ADC switch 1 */ -+#define ADV7183_ADC_SWITCH_2 0xC4 /* ADC swithc 2 */ -+#define ADV7183_LETTERBOX_CTRL_1 0xDC /* Letterbox control 1 */ -+#define ADV7183_LETTERBOX_CTRL_2 0xDD /* Letterbox control 2 */ -+#define ADV7183_SD_OFFSET_CB 0xE1 /* SD offset Cb */ -+#define ADV7183_SD_OFFSET_CR 0xE2 /* SD offset Cr */ -+#define ADV7183_SD_SATURATION_CB 0xE3 /* SD saturation Cb */ -+#define ADV7183_SD_SATURATION_CR 0xE4 /* SD saturation Cr */ -+#define ADV7183_NTSC_V_BEGIN 0xE5 /* NTSC V bit begin */ -+#define ADV7183_NTSC_V_END 0xE6 /* NTSC V bit end */ -+#define ADV7183_NTSC_F_TOGGLE 0xE7 /* NTSC F bit toggle */ -+#define ADV7183_PAL_V_BEGIN 0xE8 /* PAL V bit begin */ -+#define ADV7183_PAL_V_END 0xE9 /* PAL V bit end */ -+#define ADV7183_PAL_F_TOGGLE 0xEA /* PAL F bit toggle */ -+#define ADV7183_DRIVE_STR 0xF4 /* Drive strength */ -+#define ADV7183_IF_COMP_CTRL 0xF8 /* IF comp control */ -+#define ADV7183_VS_MODE_CTRL 0xF9 /* VS mode control */ -+ -+#endif -Index: linux-3.3.x86_64/include/media/adv7183.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/include/media/adv7183.h -@@ -0,0 +1,47 @@ -+/* -+ * adv7183.h - definition for adv7183 inputs and outputs -+ * -+ * Copyright (c) 2011 Analog Devices Inc. -+ * -+ * 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. -+ * -+ * 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 _ADV7183_H_ -+#define _ADV7183_H_ -+ -+/* ADV7183 HW inputs */ -+#define ADV7183_COMPOSITE0 0 /* CVBS in on AIN1 */ -+#define ADV7183_COMPOSITE1 1 /* CVBS in on AIN2 */ -+#define ADV7183_COMPOSITE2 2 /* CVBS in on AIN3 */ -+#define ADV7183_COMPOSITE3 3 /* CVBS in on AIN4 */ -+#define ADV7183_COMPOSITE4 4 /* CVBS in on AIN5 */ -+#define ADV7183_COMPOSITE5 5 /* CVBS in on AIN6 */ -+#define ADV7183_COMPOSITE6 6 /* CVBS in on AIN7 */ -+#define ADV7183_COMPOSITE7 7 /* CVBS in on AIN8 */ -+#define ADV7183_COMPOSITE8 8 /* CVBS in on AIN9 */ -+#define ADV7183_COMPOSITE9 9 /* CVBS in on AIN10 */ -+#define ADV7183_COMPOSITE10 10 /* CVBS in on AIN11 */ -+ -+#define ADV7183_SVIDEO0 11 /* Y on AIN1, C on AIN4 */ -+#define ADV7183_SVIDEO1 12 /* Y on AIN2, C on AIN5 */ -+#define ADV7183_SVIDEO2 13 /* Y on AIN3, C on AIN6 */ -+ -+#define ADV7183_COMPONENT0 14 /* Y on AIN1, Pr on AIN4, Pb on AIN5 */ -+#define ADV7183_COMPONENT1 15 /* Y on AIN2, Pr on AIN3, Pb on AIN6 */ -+ -+/* ADV7183 HW outputs */ -+#define ADV7183_8BIT_OUT 0 -+#define ADV7183_16BIT_OUT 1 -+ -+#endif -Index: linux-3.3.x86_64/include/media/v4l2-chip-ident.h -=================================================================== ---- linux-3.3.x86_64.orig/include/media/v4l2-chip-ident.h -+++ linux-3.3.x86_64/include/media/v4l2-chip-ident.h -@@ -143,6 +143,9 @@ enum { - /* module saa6588: just ident 6588 */ - V4L2_IDENT_SAA6588 = 6588, - -+ /* module vs6624: just ident 6624 */ -+ V4L2_IDENT_VS6624 = 6624, -+ - /* module saa6752hs: reserved range 6750-6759 */ - V4L2_IDENT_SAA6752HS = 6752, - V4L2_IDENT_SAA6752HS_AC3 = 6753, -@@ -162,6 +165,9 @@ enum { - /* module adv7180: just ident 7180 */ - V4L2_IDENT_ADV7180 = 7180, - -+ /* module adv7183: just ident 7183 */ -+ V4L2_IDENT_ADV7183 = 7183, -+ - /* module saa7185: just ident 7185 */ - V4L2_IDENT_SAA7185 = 7185, - -Index: linux-3.3.x86_64/drivers/media/video/vs6624.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/vs6624.c -@@ -0,0 +1,928 @@ -+/* -+ * vs6624.c ST VS6624 CMOS image sensor driver -+ * -+ * Copyright (c) 2011 Analog Devices Inc. -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "vs6624_regs.h" -+ -+#define VGA_WIDTH 640 -+#define VGA_HEIGHT 480 -+#define QVGA_WIDTH 320 -+#define QVGA_HEIGHT 240 -+#define QQVGA_WIDTH 160 -+#define QQVGA_HEIGHT 120 -+#define CIF_WIDTH 352 -+#define CIF_HEIGHT 288 -+#define QCIF_WIDTH 176 -+#define QCIF_HEIGHT 144 -+#define QQCIF_WIDTH 88 -+#define QQCIF_HEIGHT 72 -+ -+#define MAX_FRAME_RATE 30 -+ -+struct vs6624 { -+ struct v4l2_subdev sd; -+ struct v4l2_ctrl_handler hdl; -+ struct v4l2_fract frame_rate; -+ struct v4l2_mbus_framefmt fmt; -+ unsigned ce_pin; -+}; -+ -+static const struct vs6624_format { -+ enum v4l2_mbus_pixelcode mbus_code; -+ enum v4l2_colorspace colorspace; -+} vs6624_formats[] = { -+ { -+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+}; -+ -+static struct v4l2_mbus_framefmt vs6624_default_fmt = { -+ .width = VGA_WIDTH, -+ .height = VGA_HEIGHT, -+ .code = V4L2_MBUS_FMT_UYVY8_2X8, -+ .field = V4L2_FIELD_NONE, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+}; -+ -+static const u16 vs6624_p1[] = { -+ 0x8104, 0x03, -+ 0x8105, 0x01, -+ 0xc900, 0x03, -+ 0xc904, 0x47, -+ 0xc905, 0x10, -+ 0xc906, 0x80, -+ 0xc907, 0x3a, -+ 0x903a, 0x02, -+ 0x903b, 0x47, -+ 0x903c, 0x15, -+ 0xc908, 0x31, -+ 0xc909, 0xdc, -+ 0xc90a, 0x80, -+ 0xc90b, 0x44, -+ 0x9044, 0x02, -+ 0x9045, 0x31, -+ 0x9046, 0xe2, -+ 0xc90c, 0x07, -+ 0xc90d, 0xe0, -+ 0xc90e, 0x80, -+ 0xc90f, 0x47, -+ 0x9047, 0x90, -+ 0x9048, 0x83, -+ 0x9049, 0x81, -+ 0x904a, 0xe0, -+ 0x904b, 0x60, -+ 0x904c, 0x08, -+ 0x904d, 0x90, -+ 0x904e, 0xc0, -+ 0x904f, 0x43, -+ 0x9050, 0x74, -+ 0x9051, 0x01, -+ 0x9052, 0xf0, -+ 0x9053, 0x80, -+ 0x9054, 0x05, -+ 0x9055, 0xE4, -+ 0x9056, 0x90, -+ 0x9057, 0xc0, -+ 0x9058, 0x43, -+ 0x9059, 0xf0, -+ 0x905a, 0x02, -+ 0x905b, 0x07, -+ 0x905c, 0xec, -+ 0xc910, 0x5d, -+ 0xc911, 0xca, -+ 0xc912, 0x80, -+ 0xc913, 0x5d, -+ 0x905d, 0xa3, -+ 0x905e, 0x04, -+ 0x905f, 0xf0, -+ 0x9060, 0xa3, -+ 0x9061, 0x04, -+ 0x9062, 0xf0, -+ 0x9063, 0x22, -+ 0xc914, 0x72, -+ 0xc915, 0x92, -+ 0xc916, 0x80, -+ 0xc917, 0x64, -+ 0x9064, 0x74, -+ 0x9065, 0x01, -+ 0x9066, 0x02, -+ 0x9067, 0x72, -+ 0x9068, 0x95, -+ 0xc918, 0x47, -+ 0xc919, 0xf2, -+ 0xc91a, 0x81, -+ 0xc91b, 0x69, -+ 0x9169, 0x74, -+ 0x916a, 0x02, -+ 0x916b, 0xf0, -+ 0x916c, 0xec, -+ 0x916d, 0xb4, -+ 0x916e, 0x10, -+ 0x916f, 0x0a, -+ 0x9170, 0x90, -+ 0x9171, 0x80, -+ 0x9172, 0x16, -+ 0x9173, 0xe0, -+ 0x9174, 0x70, -+ 0x9175, 0x04, -+ 0x9176, 0x90, -+ 0x9177, 0xd3, -+ 0x9178, 0xc4, -+ 0x9179, 0xf0, -+ 0x917a, 0x22, -+ 0xc91c, 0x0a, -+ 0xc91d, 0xbe, -+ 0xc91e, 0x80, -+ 0xc91f, 0x73, -+ 0x9073, 0xfc, -+ 0x9074, 0xa3, -+ 0x9075, 0xe0, -+ 0x9076, 0xf5, -+ 0x9077, 0x82, -+ 0x9078, 0x8c, -+ 0x9079, 0x83, -+ 0x907a, 0xa3, -+ 0x907b, 0xa3, -+ 0x907c, 0xe0, -+ 0x907d, 0xfc, -+ 0x907e, 0xa3, -+ 0x907f, 0xe0, -+ 0x9080, 0xc3, -+ 0x9081, 0x9f, -+ 0x9082, 0xff, -+ 0x9083, 0xec, -+ 0x9084, 0x9e, -+ 0x9085, 0xfe, -+ 0x9086, 0x02, -+ 0x9087, 0x0a, -+ 0x9088, 0xea, -+ 0xc920, 0x47, -+ 0xc921, 0x38, -+ 0xc922, 0x80, -+ 0xc923, 0x89, -+ 0x9089, 0xec, -+ 0x908a, 0xd3, -+ 0x908b, 0x94, -+ 0x908c, 0x20, -+ 0x908d, 0x40, -+ 0x908e, 0x01, -+ 0x908f, 0x1c, -+ 0x9090, 0x90, -+ 0x9091, 0xd3, -+ 0x9092, 0xd4, -+ 0x9093, 0xec, -+ 0x9094, 0xf0, -+ 0x9095, 0x02, -+ 0x9096, 0x47, -+ 0x9097, 0x3d, -+ 0xc924, 0x45, -+ 0xc925, 0xca, -+ 0xc926, 0x80, -+ 0xc927, 0x98, -+ 0x9098, 0x12, -+ 0x9099, 0x77, -+ 0x909a, 0xd6, -+ 0x909b, 0x02, -+ 0x909c, 0x45, -+ 0x909d, 0xcd, -+ 0xc928, 0x20, -+ 0xc929, 0xd5, -+ 0xc92a, 0x80, -+ 0xc92b, 0x9e, -+ 0x909e, 0x90, -+ 0x909f, 0x82, -+ 0x90a0, 0x18, -+ 0x90a1, 0xe0, -+ 0x90a2, 0xb4, -+ 0x90a3, 0x03, -+ 0x90a4, 0x0e, -+ 0x90a5, 0x90, -+ 0x90a6, 0x83, -+ 0x90a7, 0xbf, -+ 0x90a8, 0xe0, -+ 0x90a9, 0x60, -+ 0x90aa, 0x08, -+ 0x90ab, 0x90, -+ 0x90ac, 0x81, -+ 0x90ad, 0xfc, -+ 0x90ae, 0xe0, -+ 0x90af, 0xff, -+ 0x90b0, 0xc3, -+ 0x90b1, 0x13, -+ 0x90b2, 0xf0, -+ 0x90b3, 0x90, -+ 0x90b4, 0x81, -+ 0x90b5, 0xfc, -+ 0x90b6, 0xe0, -+ 0x90b7, 0xff, -+ 0x90b8, 0x02, -+ 0x90b9, 0x20, -+ 0x90ba, 0xda, -+ 0xc92c, 0x70, -+ 0xc92d, 0xbc, -+ 0xc92e, 0x80, -+ 0xc92f, 0xbb, -+ 0x90bb, 0x90, -+ 0x90bc, 0x82, -+ 0x90bd, 0x18, -+ 0x90be, 0xe0, -+ 0x90bf, 0xb4, -+ 0x90c0, 0x03, -+ 0x90c1, 0x06, -+ 0x90c2, 0x90, -+ 0x90c3, 0xc1, -+ 0x90c4, 0x06, -+ 0x90c5, 0x74, -+ 0x90c6, 0x05, -+ 0x90c7, 0xf0, -+ 0x90c8, 0x90, -+ 0x90c9, 0xd3, -+ 0x90ca, 0xa0, -+ 0x90cb, 0x02, -+ 0x90cc, 0x70, -+ 0x90cd, 0xbf, -+ 0xc930, 0x72, -+ 0xc931, 0x21, -+ 0xc932, 0x81, -+ 0xc933, 0x3b, -+ 0x913b, 0x7d, -+ 0x913c, 0x02, -+ 0x913d, 0x7f, -+ 0x913e, 0x7b, -+ 0x913f, 0x02, -+ 0x9140, 0x72, -+ 0x9141, 0x25, -+ 0xc934, 0x28, -+ 0xc935, 0xae, -+ 0xc936, 0x80, -+ 0xc937, 0xd2, -+ 0x90d2, 0xf0, -+ 0x90d3, 0x90, -+ 0x90d4, 0xd2, -+ 0x90d5, 0x0a, -+ 0x90d6, 0x02, -+ 0x90d7, 0x28, -+ 0x90d8, 0xb4, -+ 0xc938, 0x28, -+ 0xc939, 0xb1, -+ 0xc93a, 0x80, -+ 0xc93b, 0xd9, -+ 0x90d9, 0x90, -+ 0x90da, 0x83, -+ 0x90db, 0xba, -+ 0x90dc, 0xe0, -+ 0x90dd, 0xff, -+ 0x90de, 0x90, -+ 0x90df, 0xd2, -+ 0x90e0, 0x08, -+ 0x90e1, 0xe0, -+ 0x90e2, 0xe4, -+ 0x90e3, 0xef, -+ 0x90e4, 0xf0, -+ 0x90e5, 0xa3, -+ 0x90e6, 0xe0, -+ 0x90e7, 0x74, -+ 0x90e8, 0xff, -+ 0x90e9, 0xf0, -+ 0x90ea, 0x90, -+ 0x90eb, 0xd2, -+ 0x90ec, 0x0a, -+ 0x90ed, 0x02, -+ 0x90ee, 0x28, -+ 0x90ef, 0xb4, -+ 0xc93c, 0x29, -+ 0xc93d, 0x79, -+ 0xc93e, 0x80, -+ 0xc93f, 0xf0, -+ 0x90f0, 0xf0, -+ 0x90f1, 0x90, -+ 0x90f2, 0xd2, -+ 0x90f3, 0x0e, -+ 0x90f4, 0x02, -+ 0x90f5, 0x29, -+ 0x90f6, 0x7f, -+ 0xc940, 0x29, -+ 0xc941, 0x7c, -+ 0xc942, 0x80, -+ 0xc943, 0xf7, -+ 0x90f7, 0x90, -+ 0x90f8, 0x83, -+ 0x90f9, 0xba, -+ 0x90fa, 0xe0, -+ 0x90fb, 0xff, -+ 0x90fc, 0x90, -+ 0x90fd, 0xd2, -+ 0x90fe, 0x0c, -+ 0x90ff, 0xe0, -+ 0x9100, 0xe4, -+ 0x9101, 0xef, -+ 0x9102, 0xf0, -+ 0x9103, 0xa3, -+ 0x9104, 0xe0, -+ 0x9105, 0x74, -+ 0x9106, 0xff, -+ 0x9107, 0xf0, -+ 0x9108, 0x90, -+ 0x9109, 0xd2, -+ 0x910a, 0x0e, -+ 0x910b, 0x02, -+ 0x910c, 0x29, -+ 0x910d, 0x7f, -+ 0xc944, 0x2a, -+ 0xc945, 0x42, -+ 0xc946, 0x81, -+ 0xc947, 0x0e, -+ 0x910e, 0xf0, -+ 0x910f, 0x90, -+ 0x9110, 0xd2, -+ 0x9111, 0x12, -+ 0x9112, 0x02, -+ 0x9113, 0x2a, -+ 0x9114, 0x48, -+ 0xc948, 0x2a, -+ 0xc949, 0x45, -+ 0xc94a, 0x81, -+ 0xc94b, 0x15, -+ 0x9115, 0x90, -+ 0x9116, 0x83, -+ 0x9117, 0xba, -+ 0x9118, 0xe0, -+ 0x9119, 0xff, -+ 0x911a, 0x90, -+ 0x911b, 0xd2, -+ 0x911c, 0x10, -+ 0x911d, 0xe0, -+ 0x911e, 0xe4, -+ 0x911f, 0xef, -+ 0x9120, 0xf0, -+ 0x9121, 0xa3, -+ 0x9122, 0xe0, -+ 0x9123, 0x74, -+ 0x9124, 0xff, -+ 0x9125, 0xf0, -+ 0x9126, 0x90, -+ 0x9127, 0xd2, -+ 0x9128, 0x12, -+ 0x9129, 0x02, -+ 0x912a, 0x2a, -+ 0x912b, 0x48, -+ 0xc900, 0x01, -+ 0x0000, 0x00, -+}; -+ -+static const u16 vs6624_p2[] = { -+ 0x806f, 0x01, -+ 0x058c, 0x01, -+ 0x0000, 0x00, -+}; -+ -+static const u16 vs6624_run_setup[] = { -+ 0x1d18, 0x00, /* Enableconstrainedwhitebalance */ -+ VS6624_PEAK_MIN_OUT_G_MSB, 0x3c, /* Damper PeakGain Output MSB */ -+ VS6624_PEAK_MIN_OUT_G_LSB, 0x66, /* Damper PeakGain Output LSB */ -+ VS6624_CM_LOW_THR_MSB, 0x65, /* Damper Low MSB */ -+ VS6624_CM_LOW_THR_LSB, 0xd1, /* Damper Low LSB */ -+ VS6624_CM_HIGH_THR_MSB, 0x66, /* Damper High MSB */ -+ VS6624_CM_HIGH_THR_LSB, 0x62, /* Damper High LSB */ -+ VS6624_CM_MIN_OUT_MSB, 0x00, /* Damper Min output MSB */ -+ VS6624_CM_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */ -+ VS6624_NORA_DISABLE, 0x00, /* Nora fDisable */ -+ VS6624_NORA_USAGE, 0x04, /* Nora usage */ -+ VS6624_NORA_LOW_THR_MSB, 0x63, /* Damper Low MSB Changed 0x63 to 0x65 */ -+ VS6624_NORA_LOW_THR_LSB, 0xd1, /* Damper Low LSB */ -+ VS6624_NORA_HIGH_THR_MSB, 0x68, /* Damper High MSB */ -+ VS6624_NORA_HIGH_THR_LSB, 0xdd, /* Damper High LSB */ -+ VS6624_NORA_MIN_OUT_MSB, 0x3a, /* Damper Min output MSB */ -+ VS6624_NORA_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */ -+ VS6624_F2B_DISABLE, 0x00, /* Disable */ -+ 0x1d8a, 0x30, /* MAXWeightHigh */ -+ 0x1d91, 0x62, /* fpDamperLowThresholdHigh MSB */ -+ 0x1d92, 0x4a, /* fpDamperLowThresholdHigh LSB */ -+ 0x1d95, 0x65, /* fpDamperHighThresholdHigh MSB */ -+ 0x1d96, 0x0e, /* fpDamperHighThresholdHigh LSB */ -+ 0x1da1, 0x3a, /* fpMinimumDamperOutputLow MSB */ -+ 0x1da2, 0xb8, /* fpMinimumDamperOutputLow LSB */ -+ 0x1e08, 0x06, /* MAXWeightLow */ -+ 0x1e0a, 0x0a, /* MAXWeightHigh */ -+ 0x1601, 0x3a, /* Red A MSB */ -+ 0x1602, 0x14, /* Red A LSB */ -+ 0x1605, 0x3b, /* Blue A MSB */ -+ 0x1606, 0x85, /* BLue A LSB */ -+ 0x1609, 0x3b, /* RED B MSB */ -+ 0x160a, 0x85, /* RED B LSB */ -+ 0x160d, 0x3a, /* Blue B MSB */ -+ 0x160e, 0x14, /* Blue B LSB */ -+ 0x1611, 0x30, /* Max Distance from Locus MSB */ -+ 0x1612, 0x8f, /* Max Distance from Locus MSB */ -+ 0x1614, 0x01, /* Enable constrainer */ -+ 0x0000, 0x00, -+}; -+ -+static const u16 vs6624_default[] = { -+ VS6624_CONTRAST0, 0x84, -+ VS6624_SATURATION0, 0x75, -+ VS6624_GAMMA0, 0x11, -+ VS6624_CONTRAST1, 0x84, -+ VS6624_SATURATION1, 0x75, -+ VS6624_GAMMA1, 0x11, -+ VS6624_MAN_RG, 0x80, -+ VS6624_MAN_GG, 0x80, -+ VS6624_MAN_BG, 0x80, -+ VS6624_WB_MODE, 0x1, -+ VS6624_EXPO_COMPENSATION, 0xfe, -+ VS6624_EXPO_METER, 0x0, -+ VS6624_LIGHT_FREQ, 0x64, -+ VS6624_PEAK_GAIN, 0xe, -+ VS6624_PEAK_LOW_THR, 0x28, -+ VS6624_HMIRROR0, 0x0, -+ VS6624_VFLIP0, 0x0, -+ VS6624_ZOOM_HSTEP0_MSB, 0x0, -+ VS6624_ZOOM_HSTEP0_LSB, 0x1, -+ VS6624_ZOOM_VSTEP0_MSB, 0x0, -+ VS6624_ZOOM_VSTEP0_LSB, 0x1, -+ VS6624_PAN_HSTEP0_MSB, 0x0, -+ VS6624_PAN_HSTEP0_LSB, 0xf, -+ VS6624_PAN_VSTEP0_MSB, 0x0, -+ VS6624_PAN_VSTEP0_LSB, 0xf, -+ VS6624_SENSOR_MODE, 0x1, -+ VS6624_SYNC_CODE_SETUP, 0x21, -+ VS6624_DISABLE_FR_DAMPER, 0x0, -+ VS6624_FR_DEN, 0x1, -+ VS6624_FR_NUM_LSB, 0xf, -+ VS6624_INIT_PIPE_SETUP, 0x0, -+ VS6624_IMG_FMT0, 0x0, -+ VS6624_YUV_SETUP, 0x1, -+ VS6624_IMAGE_SIZE0, 0x2, -+ 0x0000, 0x00, -+}; -+ -+static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct vs6624, sd); -+} -+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -+{ -+ return &container_of(ctrl->handler, struct vs6624, hdl)->sd; -+} -+ -+static int vs6624_read(struct v4l2_subdev *sd, u16 index) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ u8 buf[2]; -+ -+ buf[0] = index >> 8; -+ buf[1] = index; -+ i2c_master_send(client, buf, 2); -+ i2c_master_recv(client, buf, 1); -+ -+ return buf[0]; -+} -+ -+static int vs6624_write(struct v4l2_subdev *sd, u16 index, -+ u8 value) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ u8 buf[3]; -+ -+ buf[0] = index >> 8; -+ buf[1] = index; -+ buf[2] = value; -+ -+ return i2c_master_send(client, buf, 3); -+} -+ -+static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs) -+{ -+ u16 reg; -+ u8 data; -+ -+ while (*regs != 0x00) { -+ reg = *regs++; -+ data = *regs++; -+ -+ vs6624_write(sd, reg, data); -+ } -+ return 0; -+} -+ -+static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct v4l2_subdev *sd = to_sd(ctrl); -+ -+ switch (ctrl->id) { -+ case V4L2_CID_CONTRAST: -+ vs6624_write(sd, VS6624_CONTRAST0, ctrl->val); -+ break; -+ case V4L2_CID_SATURATION: -+ vs6624_write(sd, VS6624_SATURATION0, ctrl->val); -+ break; -+ case V4L2_CID_HFLIP: -+ vs6624_write(sd, VS6624_HMIRROR0, ctrl->val); -+ break; -+ case V4L2_CID_VFLIP: -+ vs6624_write(sd, VS6624_VFLIP0, ctrl->val); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, -+ enum v4l2_mbus_pixelcode *code) -+{ -+ if (index >= ARRAY_SIZE(vs6624_formats)) -+ return -EINVAL; -+ -+ *code = vs6624_formats[index].mbus_code; -+ return 0; -+} -+ -+static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *fmt) -+{ -+ int index; -+ -+ for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++) -+ if (vs6624_formats[index].mbus_code == fmt->code) -+ break; -+ if (index >= ARRAY_SIZE(vs6624_formats)) { -+ /* default to first format */ -+ index = 0; -+ fmt->code = vs6624_formats[0].mbus_code; -+ } -+ -+ /* sensor mode is VGA */ -+ if (fmt->width > VGA_WIDTH) -+ fmt->width = VGA_WIDTH; -+ if (fmt->height > VGA_HEIGHT) -+ fmt->height = VGA_HEIGHT; -+ fmt->width = fmt->width & (~3); -+ fmt->height = fmt->height & (~3); -+ fmt->field = V4L2_FIELD_NONE; -+ fmt->colorspace = vs6624_formats[index].colorspace; -+ return 0; -+} -+ -+static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *fmt) -+{ -+ struct vs6624 *sensor = to_vs6624(sd); -+ int ret; -+ -+ ret = vs6624_try_mbus_fmt(sd, fmt); -+ if (ret) -+ return ret; -+ -+ /* set image format */ -+ switch (fmt->code) { -+ case V4L2_MBUS_FMT_UYVY8_2X8: -+ vs6624_write(sd, VS6624_IMG_FMT0, 0x0); -+ vs6624_write(sd, VS6624_YUV_SETUP, 0x1); -+ break; -+ case V4L2_MBUS_FMT_YUYV8_2X8: -+ vs6624_write(sd, VS6624_IMG_FMT0, 0x0); -+ vs6624_write(sd, VS6624_YUV_SETUP, 0x3); -+ break; -+ case V4L2_MBUS_FMT_RGB565_2X8_LE: -+ vs6624_write(sd, VS6624_IMG_FMT0, 0x4); -+ vs6624_write(sd, VS6624_RGB_SETUP, 0x0); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* set image size */ -+ if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT)) -+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2); -+ else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT)) -+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4); -+ else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT)) -+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6); -+ else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT)) -+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3); -+ else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT)) -+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5); -+ else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT)) -+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7); -+ else { -+ vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8); -+ vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8); -+ vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF); -+ vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8); -+ vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF); -+ vs6624_write(sd, VS6624_CROP_CTRL0, 0x1); -+ } -+ -+ sensor->fmt = *fmt; -+ -+ return 0; -+} -+ -+static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *fmt) -+{ -+ struct vs6624 *sensor = to_vs6624(sd); -+ -+ *fmt = sensor->fmt; -+ return 0; -+} -+ -+static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -+{ -+ struct vs6624 *sensor = to_vs6624(sd); -+ struct v4l2_captureparm *cp = &parms->parm.capture; -+ -+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ -+ memset(cp, 0, sizeof(*cp)); -+ cp->capability = V4L2_CAP_TIMEPERFRAME; -+ cp->timeperframe.numerator = sensor->frame_rate.denominator; -+ cp->timeperframe.denominator = sensor->frame_rate.numerator; -+ return 0; -+} -+ -+static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -+{ -+ struct vs6624 *sensor = to_vs6624(sd); -+ struct v4l2_captureparm *cp = &parms->parm.capture; -+ struct v4l2_fract *tpf = &cp->timeperframe; -+ -+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ if (cp->extendedmode != 0) -+ return -EINVAL; -+ -+ if (tpf->numerator == 0 || tpf->denominator == 0 -+ || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) { -+ /* reset to max frame rate */ -+ tpf->numerator = 1; -+ tpf->denominator = MAX_FRAME_RATE; -+ } -+ sensor->frame_rate.numerator = tpf->denominator; -+ sensor->frame_rate.denominator = tpf->numerator; -+ vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0); -+ vs6624_write(sd, VS6624_FR_NUM_MSB, -+ sensor->frame_rate.numerator >> 8); -+ vs6624_write(sd, VS6624_FR_NUM_LSB, -+ sensor->frame_rate.numerator & 0xFF); -+ vs6624_write(sd, VS6624_FR_DEN, -+ sensor->frame_rate.denominator & 0xFF); -+ return 0; -+} -+ -+static int vs6624_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ if (enable) -+ vs6624_write(sd, VS6624_USER_CMD, 0x2); -+ else -+ vs6624_write(sd, VS6624_USER_CMD, 0x4); -+ udelay(100); -+ return 0; -+} -+ -+static int vs6624_g_chip_ident(struct v4l2_subdev *sd, -+ struct v4l2_dbg_chip_ident *chip) -+{ -+ int rev; -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8) -+ | vs6624_read(sd, VS6624_FW_VSN_MINOR); -+ -+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev); -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ reg->val = vs6624_read(sd, reg->reg & 0xffff); -+ reg->size = 1; -+ return 0; -+} -+ -+static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ if (!v4l2_chip_match_i2c_client(client, ®->match)) -+ return -EINVAL; -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff); -+ return 0; -+} -+#endif -+ -+static const struct v4l2_ctrl_ops vs6624_ctrl_ops = { -+ .s_ctrl = vs6624_s_ctrl, -+}; -+ -+static const struct v4l2_subdev_core_ops vs6624_core_ops = { -+ .g_chip_ident = vs6624_g_chip_ident, -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = vs6624_g_register, -+ .s_register = vs6624_s_register, -+#endif -+}; -+ -+static const struct v4l2_subdev_video_ops vs6624_video_ops = { -+ .enum_mbus_fmt = vs6624_enum_mbus_fmt, -+ .try_mbus_fmt = vs6624_try_mbus_fmt, -+ .s_mbus_fmt = vs6624_s_mbus_fmt, -+ .g_mbus_fmt = vs6624_g_mbus_fmt, -+ .s_parm = vs6624_s_parm, -+ .g_parm = vs6624_g_parm, -+ .s_stream = vs6624_s_stream, -+}; -+ -+static const struct v4l2_subdev_ops vs6624_ops = { -+ .core = &vs6624_core_ops, -+ .video = &vs6624_video_ops, -+}; -+ -+static int __devinit vs6624_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct vs6624 *sensor; -+ struct v4l2_subdev *sd; -+ struct v4l2_ctrl_handler *hdl; -+ const unsigned *ce; -+ int ret; -+ -+ /* Check if the adapter supports the needed features */ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) -+ return -EIO; -+ -+ ce = client->dev.platform_data; -+ if (ce == NULL) -+ return -EINVAL; -+ -+ ret = gpio_request(*ce, "VS6624 Chip Enable"); -+ if (ret) { -+ v4l_err(client, "failed to request GPIO %d\n", *ce); -+ return ret; -+ } -+ gpio_direction_output(*ce, 1); -+ /* wait 100ms before any further i2c writes are performed */ -+ mdelay(100); -+ -+ sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); -+ if (sensor == NULL) { -+ gpio_free(*ce); -+ return -ENOMEM; -+ } -+ -+ sd = &sensor->sd; -+ v4l2_i2c_subdev_init(sd, client, &vs6624_ops); -+ -+ vs6624_writeregs(sd, vs6624_p1); -+ vs6624_write(sd, VS6624_MICRO_EN, 0x2); -+ vs6624_write(sd, VS6624_DIO_EN, 0x1); -+ mdelay(10); -+ vs6624_writeregs(sd, vs6624_p2); -+ -+ vs6624_writeregs(sd, vs6624_default); -+ vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF); -+ vs6624_writeregs(sd, vs6624_run_setup); -+ -+ /* set frame rate */ -+ sensor->frame_rate.numerator = MAX_FRAME_RATE; -+ sensor->frame_rate.denominator = 1; -+ vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0); -+ vs6624_write(sd, VS6624_FR_NUM_MSB, -+ sensor->frame_rate.numerator >> 8); -+ vs6624_write(sd, VS6624_FR_NUM_LSB, -+ sensor->frame_rate.numerator & 0xFF); -+ vs6624_write(sd, VS6624_FR_DEN, -+ sensor->frame_rate.denominator & 0xFF); -+ -+ sensor->fmt = vs6624_default_fmt; -+ sensor->ce_pin = *ce; -+ -+ v4l_info(client, "chip found @ 0x%02x (%s)\n", -+ client->addr << 1, client->adapter->name); -+ -+ hdl = &sensor->hdl; -+ v4l2_ctrl_handler_init(hdl, 4); -+ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, -+ V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87); -+ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, -+ V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78); -+ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, -+ V4L2_CID_HFLIP, 0, 1, 1, 0); -+ v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops, -+ V4L2_CID_VFLIP, 0, 1, 1, 0); -+ /* hook the control handler into the driver */ -+ sd->ctrl_handler = hdl; -+ if (hdl->error) { -+ int err = hdl->error; -+ -+ v4l2_ctrl_handler_free(hdl); -+ kfree(sensor); -+ gpio_free(*ce); -+ return err; -+ } -+ -+ /* initialize the hardware to the default control values */ -+ ret = v4l2_ctrl_handler_setup(hdl); -+ if (ret) { -+ v4l2_ctrl_handler_free(hdl); -+ kfree(sensor); -+ gpio_free(*ce); -+ } -+ return ret; -+} -+ -+static int __devexit vs6624_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct vs6624 *sensor = to_vs6624(sd); -+ -+ v4l2_device_unregister_subdev(sd); -+ v4l2_ctrl_handler_free(sd->ctrl_handler); -+ gpio_free(sensor->ce_pin); -+ kfree(sensor); -+ return 0; -+} -+ -+static const struct i2c_device_id vs6624_id[] = { -+ {"vs6624", 0}, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(i2c, vs6624_id); -+ -+static struct i2c_driver vs6624_driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "vs6624", -+ }, -+ .probe = vs6624_probe, -+ .remove = __devexit_p(vs6624_remove), -+ .id_table = vs6624_id, -+}; -+ -+static __init int vs6624_init(void) -+{ -+ return i2c_add_driver(&vs6624_driver); -+} -+ -+static __exit void vs6624_exit(void) -+{ -+ i2c_del_driver(&vs6624_driver); -+} -+ -+module_init(vs6624_init); -+module_exit(vs6624_exit); -+ -+MODULE_DESCRIPTION("VS6624 sensor driver"); -+MODULE_AUTHOR("Scott Jiang "); -+MODULE_LICENSE("GPL v2"); -Index: linux-3.3.x86_64/drivers/media/video/vs6624_regs.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/vs6624_regs.h -@@ -0,0 +1,337 @@ -+/* -+ * vs6624 - ST VS6624 CMOS image sensor registers -+ * -+ * Copyright (c) 2011 Analog Devices Inc. -+ * -+ * 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. -+ * -+ * 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 _VS6624_REGS_H_ -+#define _VS6624_REGS_H_ -+ -+/* low level control registers */ -+#define VS6624_MICRO_EN 0xC003 /* power enable for all MCU clock */ -+#define VS6624_DIO_EN 0xC044 /* enable digital I/O */ -+/* device parameters */ -+#define VS6624_DEV_ID_MSB 0x0001 /* device id MSB */ -+#define VS6624_DEV_ID_LSB 0x0002 /* device id LSB */ -+#define VS6624_FW_VSN_MAJOR 0x0004 /* firmware version major */ -+#define VS6624_FW_VSN_MINOR 0x0006 /* firmware version minor */ -+#define VS6624_PATCH_VSN_MAJOR 0x0008 /* patch version major */ -+#define VS6624_PATCH_VSN_MINOR 0x000A /* patch version minor */ -+/* host interface manager control */ -+#define VS6624_USER_CMD 0x0180 /* user level control of operating states */ -+/* host interface manager status */ -+#define VS6624_STATE 0x0202 /* current state of the mode manager */ -+/* run mode control */ -+#define VS6624_METER_ON 0x0280 /* if false AE and AWB are disabled */ -+/* mode setup */ -+#define VS6624_ACTIVE_PIPE_SETUP 0x0302 /* select the active bank for non view live mode */ -+#define VS6624_SENSOR_MODE 0x0308 /* select the different sensor mode */ -+/* pipe setup bank0 */ -+#define VS6624_IMAGE_SIZE0 0x0380 /* required output dimension */ -+#define VS6624_MAN_HSIZE0_MSB 0x0383 /* input required manual H size MSB */ -+#define VS6624_MAN_HSIZE0_LSB 0x0384 /* input required manual H size LSB */ -+#define VS6624_MAN_VSIZE0_MSB 0x0387 /* input required manual V size MSB */ -+#define VS6624_MAN_VSIZE0_LSB 0x0388 /* input required manual V size LSB */ -+#define VS6624_ZOOM_HSTEP0_MSB 0x038B /* set the zoom H step MSB */ -+#define VS6624_ZOOM_HSTEP0_LSB 0x038C /* set the zoom H step LSB */ -+#define VS6624_ZOOM_VSTEP0_MSB 0x038F /* set the zoom V step MSB */ -+#define VS6624_ZOOM_VSTEP0_LSB 0x0390 /* set the zoom V step LSB */ -+#define VS6624_ZOOM_CTRL0 0x0392 /* control zoon in, out and stop */ -+#define VS6624_PAN_HSTEP0_MSB 0x0395 /* set the pan H step MSB */ -+#define VS6624_PAN_HSTEP0_LSB 0x0396 /* set the pan H step LSB */ -+#define VS6624_PAN_VSTEP0_MSB 0x0399 /* set the pan V step MSB */ -+#define VS6624_PAN_VSTEP0_LSB 0x039A /* set the pan V step LSB */ -+#define VS6624_PAN_CTRL0 0x039C /* control pan operation */ -+#define VS6624_CROP_CTRL0 0x039E /* select cropping mode */ -+#define VS6624_CROP_HSTART0_MSB 0x03A1 /* set the cropping H start address MSB */ -+#define VS6624_CROP_HSTART0_LSB 0x03A2 /* set the cropping H start address LSB */ -+#define VS6624_CROP_HSIZE0_MSB 0x03A5 /* set the cropping H size MSB */ -+#define VS6624_CROP_HSIZE0_LSB 0x03A6 /* set the cropping H size LSB */ -+#define VS6624_CROP_VSTART0_MSB 0x03A9 /* set the cropping V start address MSB */ -+#define VS6624_CROP_VSTART0_LSB 0x03AA /* set the cropping V start address LSB */ -+#define VS6624_CROP_VSIZE0_MSB 0x03AD /* set the cropping V size MSB */ -+#define VS6624_CROP_VSIZE0_LSB 0x03AE /* set the cropping V size LSB */ -+#define VS6624_IMG_FMT0 0x03B0 /* select required output image format */ -+#define VS6624_BAYER_OUT_ALIGN0 0x03B2 /* set bayer output alignment */ -+#define VS6624_CONTRAST0 0x03B4 /* contrast control for output */ -+#define VS6624_SATURATION0 0x03B6 /* saturation control for output */ -+#define VS6624_GAMMA0 0x03B8 /* gamma settings */ -+#define VS6624_HMIRROR0 0x03BA /* horizontal image orientation flip */ -+#define VS6624_VFLIP0 0x03BC /* vertical image orientation flip */ -+#define VS6624_CHANNEL_ID0 0x03BE /* logical DMA channel number */ -+/* pipe setup bank1 */ -+#define VS6624_IMAGE_SIZE1 0x0400 /* required output dimension */ -+#define VS6624_MAN_HSIZE1_MSB 0x0403 /* input required manual H size MSB */ -+#define VS6624_MAN_HSIZE1_LSB 0x0404 /* input required manual H size LSB */ -+#define VS6624_MAN_VSIZE1_MSB 0x0407 /* input required manual V size MSB */ -+#define VS6624_MAN_VSIZE1_LSB 0x0408 /* input required manual V size LSB */ -+#define VS6624_ZOOM_HSTEP1_MSB 0x040B /* set the zoom H step MSB */ -+#define VS6624_ZOOM_HSTEP1_LSB 0x040C /* set the zoom H step LSB */ -+#define VS6624_ZOOM_VSTEP1_MSB 0x040F /* set the zoom V step MSB */ -+#define VS6624_ZOOM_VSTEP1_LSB 0x0410 /* set the zoom V step LSB */ -+#define VS6624_ZOOM_CTRL1 0x0412 /* control zoon in, out and stop */ -+#define VS6624_PAN_HSTEP1_MSB 0x0415 /* set the pan H step MSB */ -+#define VS6624_PAN_HSTEP1_LSB 0x0416 /* set the pan H step LSB */ -+#define VS6624_PAN_VSTEP1_MSB 0x0419 /* set the pan V step MSB */ -+#define VS6624_PAN_VSTEP1_LSB 0x041A /* set the pan V step LSB */ -+#define VS6624_PAN_CTRL1 0x041C /* control pan operation */ -+#define VS6624_CROP_CTRL1 0x041E /* select cropping mode */ -+#define VS6624_CROP_HSTART1_MSB 0x0421 /* set the cropping H start address MSB */ -+#define VS6624_CROP_HSTART1_LSB 0x0422 /* set the cropping H start address LSB */ -+#define VS6624_CROP_HSIZE1_MSB 0x0425 /* set the cropping H size MSB */ -+#define VS6624_CROP_HSIZE1_LSB 0x0426 /* set the cropping H size LSB */ -+#define VS6624_CROP_VSTART1_MSB 0x0429 /* set the cropping V start address MSB */ -+#define VS6624_CROP_VSTART1_LSB 0x042A /* set the cropping V start address LSB */ -+#define VS6624_CROP_VSIZE1_MSB 0x042D /* set the cropping V size MSB */ -+#define VS6624_CROP_VSIZE1_LSB 0x042E /* set the cropping V size LSB */ -+#define VS6624_IMG_FMT1 0x0430 /* select required output image format */ -+#define VS6624_BAYER_OUT_ALIGN1 0x0432 /* set bayer output alignment */ -+#define VS6624_CONTRAST1 0x0434 /* contrast control for output */ -+#define VS6624_SATURATION1 0x0436 /* saturation control for output */ -+#define VS6624_GAMMA1 0x0438 /* gamma settings */ -+#define VS6624_HMIRROR1 0x043A /* horizontal image orientation flip */ -+#define VS6624_VFLIP1 0x043C /* vertical image orientation flip */ -+#define VS6624_CHANNEL_ID1 0x043E /* logical DMA channel number */ -+/* view live control */ -+#define VS6624_VIEW_LIVE_EN 0x0480 /* enable view live mode */ -+#define VS6624_INIT_PIPE_SETUP 0x0482 /* select initial pipe setup bank */ -+/* view live status */ -+#define VS6624_CUR_PIPE_SETUP 0x0500 /* indicates most recently applied setup bank */ -+/* power management */ -+#define VS6624_TIME_TO_POWER_DOWN 0x0580 /* automatically transition time to stop mode */ -+/* video timing parameter host inputs */ -+#define VS6624_EXT_CLK_FREQ_NUM_MSB 0x0605 /* external clock frequency numerator MSB */ -+#define VS6624_EXT_CLK_FREQ_NUM_LSB 0x0606 /* external clock frequency numerator LSB */ -+#define VS6624_EXT_CLK_FREQ_DEN 0x0608 /* external clock frequency denominator */ -+/* video timing control */ -+#define VS6624_SYS_CLK_MODE 0x0880 /* decides system clock frequency */ -+/* frame dimension parameter host inputs */ -+#define VS6624_LIGHT_FREQ 0x0C80 /* AC frequency used for flicker free time */ -+#define VS6624_FLICKER_COMPAT 0x0C82 /* flicker compatible frame length */ -+/* static frame rate control */ -+#define VS6624_FR_NUM_MSB 0x0D81 /* desired frame rate numerator MSB */ -+#define VS6624_FR_NUM_LSB 0x0D82 /* desired frame rate numerator LSB */ -+#define VS6624_FR_DEN 0x0D84 /* desired frame rate denominator */ -+/* automatic frame rate control */ -+#define VS6624_DISABLE_FR_DAMPER 0x0E80 /* defines frame rate mode */ -+#define VS6624_MIN_DAMPER_OUT_MSB 0x0E8C /* minimum frame rate MSB */ -+#define VS6624_MIN_DAMPER_OUT_LSB 0x0E8A /* minimum frame rate LSB */ -+/* exposure controls */ -+#define VS6624_EXPO_MODE 0x1180 /* exposure mode */ -+#define VS6624_EXPO_METER 0x1182 /* weights to be associated with the zones */ -+#define VS6624_EXPO_TIME_NUM 0x1184 /* exposure time numerator */ -+#define VS6624_EXPO_TIME_DEN 0x1186 /* exposure time denominator */ -+#define VS6624_EXPO_TIME_MSB 0x1189 /* exposure time for the Manual Mode MSB */ -+#define VS6624_EXPO_TIME_LSB 0x118A /* exposure time for the Manual Mode LSB */ -+#define VS6624_EXPO_COMPENSATION 0x1190 /* exposure compensation */ -+#define VS6624_DIRECT_COARSE_MSB 0x1195 /* coarse integration lines for Direct Mode MSB */ -+#define VS6624_DIRECT_COARSE_LSB 0x1196 /* coarse integration lines for Direct Mode LSB */ -+#define VS6624_DIRECT_FINE_MSB 0x1199 /* fine integration pixels for Direct Mode MSB */ -+#define VS6624_DIRECT_FINE_LSB 0x119A /* fine integration pixels for Direct Mode LSB */ -+#define VS6624_DIRECT_ANAL_GAIN_MSB 0x119D /* analog gain for Direct Mode MSB */ -+#define VS6624_DIRECT_ANAL_GAIN_LSB 0x119E /* analog gain for Direct Mode LSB */ -+#define VS6624_DIRECT_DIGI_GAIN_MSB 0x11A1 /* digital gain for Direct Mode MSB */ -+#define VS6624_DIRECT_DIGI_GAIN_LSB 0x11A2 /* digital gain for Direct Mode LSB */ -+#define VS6624_FLASH_COARSE_MSB 0x11A5 /* coarse integration lines for Flash Gun Mode MSB */ -+#define VS6624_FLASH_COARSE_LSB 0x11A6 /* coarse integration lines for Flash Gun Mode LSB */ -+#define VS6624_FLASH_FINE_MSB 0x11A9 /* fine integration pixels for Flash Gun Mode MSB */ -+#define VS6624_FLASH_FINE_LSB 0x11AA /* fine integration pixels for Flash Gun Mode LSB */ -+#define VS6624_FLASH_ANAL_GAIN_MSB 0x11AD /* analog gain for Flash Gun Mode MSB */ -+#define VS6624_FLASH_ANAL_GAIN_LSB 0x11AE /* analog gain for Flash Gun Mode LSB */ -+#define VS6624_FLASH_DIGI_GAIN_MSB 0x11B1 /* digital gain for Flash Gun Mode MSB */ -+#define VS6624_FLASH_DIGI_GAIN_LSB 0x11B2 /* digital gain for Flash Gun Mode LSB */ -+#define VS6624_FREEZE_AE 0x11B4 /* freeze auto exposure */ -+#define VS6624_MAX_INT_TIME_MSB 0x11B7 /* user maximum integration time MSB */ -+#define VS6624_MAX_INT_TIME_LSB 0x11B8 /* user maximum integration time LSB */ -+#define VS6624_FLASH_AG_THR_MSB 0x11BB /* recommend flash gun analog gain threshold MSB */ -+#define VS6624_FLASH_AG_THR_LSB 0x11BC /* recommend flash gun analog gain threshold LSB */ -+#define VS6624_ANTI_FLICKER_MODE 0x11C0 /* anti flicker mode */ -+/* white balance control */ -+#define VS6624_WB_MODE 0x1480 /* set white balance mode */ -+#define VS6624_MAN_RG 0x1482 /* user setting for red channel gain */ -+#define VS6624_MAN_GG 0x1484 /* user setting for green channel gain */ -+#define VS6624_MAN_BG 0x1486 /* user setting for blue channel gain */ -+#define VS6624_FLASH_RG_MSB 0x148B /* red gain for Flash Gun MSB */ -+#define VS6624_FLASH_RG_LSB 0x148C /* red gain for Flash Gun LSB */ -+#define VS6624_FLASH_GG_MSB 0x148F /* green gain for Flash Gun MSB */ -+#define VS6624_FLASH_GG_LSB 0x1490 /* green gain for Flash Gun LSB */ -+#define VS6624_FLASH_BG_MSB 0x1493 /* blue gain for Flash Gun MSB */ -+#define VS6624_FLASH_BG_LSB 0x1494 /* blue gain for Flash Gun LSB */ -+/* sensor setup */ -+#define VS6624_BC_OFFSET 0x1990 /* Black Correction Offset */ -+/* image stability */ -+#define VS6624_STABLE_WB 0x1900 /* white balance stable */ -+#define VS6624_STABLE_EXPO 0x1902 /* exposure stable */ -+#define VS6624_STABLE 0x1906 /* system stable */ -+/* flash control */ -+#define VS6624_FLASH_MODE 0x1A80 /* flash mode */ -+#define VS6624_FLASH_OFF_LINE_MSB 0x1A83 /* off line at flash pulse mode MSB */ -+#define VS6624_FLASH_OFF_LINE_LSB 0x1A84 /* off line at flash pulse mode LSB */ -+/* flash status */ -+#define VS6624_FLASH_RECOM 0x1B00 /* flash gun is recommended */ -+#define VS6624_FLASH_GRAB_COMPLETE 0x1B02 /* flash gun image has been grabbed */ -+/* scythe filter controls */ -+#define VS6624_SCYTHE_FILTER 0x1D80 /* disable scythe defect correction */ -+/* jack filter controls */ -+#define VS6624_JACK_FILTER 0x1E00 /* disable jack defect correction */ -+/* demosaic control */ -+#define VS6624_ANTI_ALIAS_FILTER 0x1E80 /* anti alias filter suppress */ -+/* color matrix dampers */ -+#define VS6624_CM_DISABLE 0x1F00 /* disable color matrix damper */ -+#define VS6624_CM_LOW_THR_MSB 0x1F03 /* low threshold for exposure MSB */ -+#define VS6624_CM_LOW_THR_LSB 0x1F04 /* low threshold for exposure LSB */ -+#define VS6624_CM_HIGH_THR_MSB 0x1F07 /* high threshold for exposure MSB */ -+#define VS6624_CM_HIGH_THR_LSB 0x1F08 /* high threshold for exposure LSB */ -+#define VS6624_CM_MIN_OUT_MSB 0x1F0B /* minimum possible damper output MSB */ -+#define VS6624_CM_MIN_OUT_LSB 0x1F0C /* minimum possible damper output LSB */ -+/* peaking control */ -+#define VS6624_PEAK_GAIN 0x2000 /* controls peaking gain */ -+#define VS6624_PEAK_G_DISABLE 0x2002 /* disable peak gain damping */ -+#define VS6624_PEAK_LOW_THR_G_MSB 0x2005 /* low threshold for exposure for gain MSB */ -+#define VS6624_PEAK_LOW_THR_G_LSB 0x2006 /* low threshold for exposure for gain LSB */ -+#define VS6624_PEAK_HIGH_THR_G_MSB 0x2009 /* high threshold for exposure for gain MSB */ -+#define VS6624_PEAK_HIGH_THR_G_LSB 0x200A /* high threshold for exposure for gain LSB */ -+#define VS6624_PEAK_MIN_OUT_G_MSB 0x200D /* minimum damper output for gain MSB */ -+#define VS6624_PEAK_MIN_OUT_G_LSB 0x200E /* minimum damper output for gain LSB */ -+#define VS6624_PEAK_LOW_THR 0x2010 /* adjust degree of coring */ -+#define VS6624_PEAK_C_DISABLE 0x2012 /* disable coring damping */ -+#define VS6624_PEAK_HIGH_THR 0x2014 /* adjust maximum gain */ -+#define VS6624_PEAK_LOW_THR_C_MSB 0x2017 /* low threshold for exposure for coring MSB */ -+#define VS6624_PEAK_LOW_THR_C_LSB 0x2018 /* low threshold for exposure for coring LSB */ -+#define VS6624_PEAK_HIGH_THR_C_MSB 0x201B /* high threshold for exposure for coring MSB */ -+#define VS6624_PEAK_HIGH_THR_C_LSB 0x201C /* high threshold for exposure for coring LSB */ -+#define VS6624_PEAK_MIN_OUT_C_MSB 0x201F /* minimum damper output for coring MSB */ -+#define VS6624_PEAK_MIN_OUT_C_LSB 0x2020 /* minimum damper output for coring LSB */ -+/* pipe 0 RGB to YUV matrix manual control */ -+#define VS6624_RYM0_MAN_CTRL 0x2180 /* enable manual RGB to YUV matrix */ -+#define VS6624_RYM0_W00_MSB 0x2183 /* row 0 column 0 of YUV matrix MSB */ -+#define VS6624_RYM0_W00_LSB 0x2184 /* row 0 column 0 of YUV matrix LSB */ -+#define VS6624_RYM0_W01_MSB 0x2187 /* row 0 column 1 of YUV matrix MSB */ -+#define VS6624_RYM0_W01_LSB 0x2188 /* row 0 column 1 of YUV matrix LSB */ -+#define VS6624_RYM0_W02_MSB 0x218C /* row 0 column 2 of YUV matrix MSB */ -+#define VS6624_RYM0_W02_LSB 0x218D /* row 0 column 2 of YUV matrix LSB */ -+#define VS6624_RYM0_W10_MSB 0x2190 /* row 1 column 0 of YUV matrix MSB */ -+#define VS6624_RYM0_W10_LSB 0x218F /* row 1 column 0 of YUV matrix LSB */ -+#define VS6624_RYM0_W11_MSB 0x2193 /* row 1 column 1 of YUV matrix MSB */ -+#define VS6624_RYM0_W11_LSB 0x2194 /* row 1 column 1 of YUV matrix LSB */ -+#define VS6624_RYM0_W12_MSB 0x2197 /* row 1 column 2 of YUV matrix MSB */ -+#define VS6624_RYM0_W12_LSB 0x2198 /* row 1 column 2 of YUV matrix LSB */ -+#define VS6624_RYM0_W20_MSB 0x219B /* row 2 column 0 of YUV matrix MSB */ -+#define VS6624_RYM0_W20_LSB 0x219C /* row 2 column 0 of YUV matrix LSB */ -+#define VS6624_RYM0_W21_MSB 0x21A0 /* row 2 column 1 of YUV matrix MSB */ -+#define VS6624_RYM0_W21_LSB 0x219F /* row 2 column 1 of YUV matrix LSB */ -+#define VS6624_RYM0_W22_MSB 0x21A3 /* row 2 column 2 of YUV matrix MSB */ -+#define VS6624_RYM0_W22_LSB 0x21A4 /* row 2 column 2 of YUV matrix LSB */ -+#define VS6624_RYM0_YINY_MSB 0x21A7 /* Y in Y MSB */ -+#define VS6624_RYM0_YINY_LSB 0x21A8 /* Y in Y LSB */ -+#define VS6624_RYM0_YINCB_MSB 0x21AB /* Y in Cb MSB */ -+#define VS6624_RYM0_YINCB_LSB 0x21AC /* Y in Cb LSB */ -+#define VS6624_RYM0_YINCR_MSB 0x21B0 /* Y in Cr MSB */ -+#define VS6624_RYM0_YINCR_LSB 0x21AF /* Y in Cr LSB */ -+/* pipe 1 RGB to YUV matrix manual control */ -+#define VS6624_RYM1_MAN_CTRL 0x2200 /* enable manual RGB to YUV matrix */ -+#define VS6624_RYM1_W00_MSB 0x2203 /* row 0 column 0 of YUV matrix MSB */ -+#define VS6624_RYM1_W00_LSB 0x2204 /* row 0 column 0 of YUV matrix LSB */ -+#define VS6624_RYM1_W01_MSB 0x2207 /* row 0 column 1 of YUV matrix MSB */ -+#define VS6624_RYM1_W01_LSB 0x2208 /* row 0 column 1 of YUV matrix LSB */ -+#define VS6624_RYM1_W02_MSB 0x220C /* row 0 column 2 of YUV matrix MSB */ -+#define VS6624_RYM1_W02_LSB 0x220D /* row 0 column 2 of YUV matrix LSB */ -+#define VS6624_RYM1_W10_MSB 0x2210 /* row 1 column 0 of YUV matrix MSB */ -+#define VS6624_RYM1_W10_LSB 0x220F /* row 1 column 0 of YUV matrix LSB */ -+#define VS6624_RYM1_W11_MSB 0x2213 /* row 1 column 1 of YUV matrix MSB */ -+#define VS6624_RYM1_W11_LSB 0x2214 /* row 1 column 1 of YUV matrix LSB */ -+#define VS6624_RYM1_W12_MSB 0x2217 /* row 1 column 2 of YUV matrix MSB */ -+#define VS6624_RYM1_W12_LSB 0x2218 /* row 1 column 2 of YUV matrix LSB */ -+#define VS6624_RYM1_W20_MSB 0x221B /* row 2 column 0 of YUV matrix MSB */ -+#define VS6624_RYM1_W20_LSB 0x221C /* row 2 column 0 of YUV matrix LSB */ -+#define VS6624_RYM1_W21_MSB 0x2220 /* row 2 column 1 of YUV matrix MSB */ -+#define VS6624_RYM1_W21_LSB 0x221F /* row 2 column 1 of YUV matrix LSB */ -+#define VS6624_RYM1_W22_MSB 0x2223 /* row 2 column 2 of YUV matrix MSB */ -+#define VS6624_RYM1_W22_LSB 0x2224 /* row 2 column 2 of YUV matrix LSB */ -+#define VS6624_RYM1_YINY_MSB 0x2227 /* Y in Y MSB */ -+#define VS6624_RYM1_YINY_LSB 0x2228 /* Y in Y LSB */ -+#define VS6624_RYM1_YINCB_MSB 0x222B /* Y in Cb MSB */ -+#define VS6624_RYM1_YINCB_LSB 0x222C /* Y in Cb LSB */ -+#define VS6624_RYM1_YINCR_MSB 0x2220 /* Y in Cr MSB */ -+#define VS6624_RYM1_YINCR_LSB 0x222F /* Y in Cr LSB */ -+/* pipe 0 gamma manual control */ -+#define VS6624_GAMMA_MAN_CTRL0 0x2280 /* enable manual gamma setup */ -+#define VS6624_GAMMA_PEAK_R0 0x2282 /* peaked red channel gamma value */ -+#define VS6624_GAMMA_PEAK_G0 0x2284 /* peaked green channel gamma value */ -+#define VS6624_GAMMA_PEAK_B0 0x2286 /* peaked blue channel gamma value */ -+#define VS6624_GAMMA_UNPEAK_R0 0x2288 /* unpeaked red channel gamma value */ -+#define VS6624_GAMMA_UNPEAK_G0 0x228A /* unpeaked green channel gamma value */ -+#define VS6624_GAMMA_UNPEAK_B0 0x228C /* unpeaked blue channel gamma value */ -+/* pipe 1 gamma manual control */ -+#define VS6624_GAMMA_MAN_CTRL1 0x2300 /* enable manual gamma setup */ -+#define VS6624_GAMMA_PEAK_R1 0x2302 /* peaked red channel gamma value */ -+#define VS6624_GAMMA_PEAK_G1 0x2304 /* peaked green channel gamma value */ -+#define VS6624_GAMMA_PEAK_B1 0x2306 /* peaked blue channel gamma value */ -+#define VS6624_GAMMA_UNPEAK_R1 0x2308 /* unpeaked red channel gamma value */ -+#define VS6624_GAMMA_UNPEAK_G1 0x230A /* unpeaked green channel gamma value */ -+#define VS6624_GAMMA_UNPEAK_B1 0x230C /* unpeaked blue channel gamma value */ -+/* fade to black */ -+#define VS6624_F2B_DISABLE 0x2480 /* disable fade to black */ -+#define VS6624_F2B_BLACK_VAL_MSB 0x2483 /* black value MSB */ -+#define VS6624_F2B_BLACK_VAL_LSB 0x2484 /* black value LSB */ -+#define VS6624_F2B_LOW_THR_MSB 0x2487 /* low threshold for exposure MSB */ -+#define VS6624_F2B_LOW_THR_LSB 0x2488 /* low threshold for exposure LSB */ -+#define VS6624_F2B_HIGH_THR_MSB 0x248B /* high threshold for exposure MSB */ -+#define VS6624_F2B_HIGH_THR_LSB 0x248C /* high threshold for exposure LSB */ -+#define VS6624_F2B_MIN_OUT_MSB 0x248F /* minimum damper output MSB */ -+#define VS6624_F2B_MIN_OUT_LSB 0x2490 /* minimum damper output LSB */ -+/* output formatter control */ -+#define VS6624_CODE_CK_EN 0x2580 /* code check enable */ -+#define VS6624_BLANK_FMT 0x2582 /* blank format */ -+#define VS6624_SYNC_CODE_SETUP 0x2584 /* sync code setup */ -+#define VS6624_HSYNC_SETUP 0x2586 /* H sync setup */ -+#define VS6624_VSYNC_SETUP 0x2588 /* V sync setup */ -+#define VS6624_PCLK_SETUP 0x258A /* PCLK setup */ -+#define VS6624_PCLK_EN 0x258C /* PCLK enable */ -+#define VS6624_OPF_SP_SETUP 0x258E /* output formatter sp setup */ -+#define VS6624_BLANK_DATA_MSB 0x2590 /* blank data MSB */ -+#define VS6624_BLANK_DATA_LSB 0x2592 /* blank data LSB */ -+#define VS6624_RGB_SETUP 0x2594 /* RGB setup */ -+#define VS6624_YUV_SETUP 0x2596 /* YUV setup */ -+#define VS6624_VSYNC_RIS_COARSE_H 0x2598 /* V sync rising coarse high */ -+#define VS6624_VSYNC_RIS_COARSE_L 0x259A /* V sync rising coarse low */ -+#define VS6624_VSYNC_RIS_FINE_H 0x259C /* V sync rising fine high */ -+#define VS6624_VSYNC_RIS_FINE_L 0x259E /* V sync rising fine low */ -+#define VS6624_VSYNC_FALL_COARSE_H 0x25A0 /* V sync falling coarse high */ -+#define VS6624_VSYNC_FALL_COARSE_L 0x25A2 /* V sync falling coarse low */ -+#define VS6624_VSYNC_FALL_FINE_H 0x25A4 /* V sync falling fine high */ -+#define VS6624_VSYNC_FALL_FINE_L 0x25A6 /* V sync falling fine low */ -+#define VS6624_HSYNC_RIS_H 0x25A8 /* H sync rising high */ -+#define VS6624_HSYNC_RIS_L 0x25AA /* H sync rising low */ -+#define VS6624_HSYNC_FALL_H 0x25AC /* H sync falling high */ -+#define VS6624_HSYNC_FALL_L 0x25AE /* H sync falling low */ -+#define VS6624_OUT_IF 0x25B0 /* output interface */ -+#define VS6624_CCP_EXT_DATA 0x25B2 /* CCP extra data */ -+/* NoRA controls */ -+#define VS6624_NORA_DISABLE 0x2600 /* NoRA control mode */ -+#define VS6624_NORA_USAGE 0x2602 /* usage */ -+#define VS6624_NORA_SPLIT_KN 0x2604 /* split kn */ -+#define VS6624_NORA_SPLIT_NI 0x2606 /* split ni */ -+#define VS6624_NORA_TIGHT_G 0x2608 /* tight green */ -+#define VS6624_NORA_DISABLE_NP 0x260A /* disable noro promoting */ -+#define VS6624_NORA_LOW_THR_MSB 0x260D /* low threshold for exposure MSB */ -+#define VS6624_NORA_LOW_THR_LSB 0x260E /* low threshold for exposure LSB */ -+#define VS6624_NORA_HIGH_THR_MSB 0x2611 /* high threshold for exposure MSB */ -+#define VS6624_NORA_HIGH_THR_LSB 0x2612 /* high threshold for exposure LSB */ -+#define VS6624_NORA_MIN_OUT_MSB 0x2615 /* minimum damper output MSB */ -+#define VS6624_NORA_MIN_OUT_LSB 0x2616 /* minimum damper output LSB */ -+ -+#endif -Index: linux-3.3.x86_64/drivers/media/video/blackfin/Kconfig -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/blackfin/Kconfig -@@ -0,0 +1,10 @@ -+config VIDEO_BLACKFIN_CAPTURE -+ tristate "Blackfin Video Capture Driver" -+ depends on VIDEO_V4L2 && BLACKFIN && I2C -+ select VIDEOBUF2_DMA_CONTIG -+ help -+ V4L2 bridge driver for Blackfin video capture device. -+ Choose PPI or EPPI as its interface. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called bfin_video_capture. -Index: linux-3.3.x86_64/drivers/media/video/blackfin/Makefile -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/blackfin/Makefile -@@ -0,0 +1,2 @@ -+bfin_video_capture-objs := bfin_capture.o ppi.o -+obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o -Index: linux-3.3.x86_64/drivers/media/video/blackfin/bfin_capture.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/blackfin/bfin_capture.c -@@ -0,0 +1,1059 @@ -+/* -+ * Analog Devices video capture driver -+ * -+ * Copyright (c) 2011 Analog Devices Inc. -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+ -+#define CAPTURE_DRV_NAME "bfin_capture" -+#define BCAP_MIN_NUM_BUF 2 -+ -+struct bcap_format { -+ char *desc; -+ u32 pixelformat; -+ enum v4l2_mbus_pixelcode mbus_code; -+ int bpp; /* bits per pixel */ -+}; -+ -+struct bcap_buffer { -+ struct vb2_buffer vb; -+ struct list_head list; -+}; -+ -+struct bcap_device { -+ /* capture device instance */ -+ struct v4l2_device v4l2_dev; -+ /* v4l2 control handler */ -+ struct v4l2_ctrl_handler ctrl_handler; -+ /* device node data */ -+ struct video_device *video_dev; -+ /* sub device instance */ -+ struct v4l2_subdev *sd; -+ /* capture config */ -+ struct bfin_capture_config *cfg; -+ /* ppi interface */ -+ struct ppi_if *ppi; -+ /* current input */ -+ unsigned int cur_input; -+ /* current selected standard */ -+ v4l2_std_id std; -+ /* used to store pixel format */ -+ struct v4l2_pix_format fmt; -+ /* bits per pixel*/ -+ int bpp; -+ /* used to store sensor supported format */ -+ struct bcap_format *sensor_formats; -+ /* number of sensor formats array */ -+ int num_sensor_formats; -+ /* pointing to current video buffer */ -+ struct bcap_buffer *cur_frm; -+ /* pointing to next video buffer */ -+ struct bcap_buffer *next_frm; -+ /* buffer queue used in videobuf2 */ -+ struct vb2_queue buffer_queue; -+ /* allocator-specific contexts for each plane */ -+ struct vb2_alloc_ctx *alloc_ctx; -+ /* queue of filled frames */ -+ struct list_head dma_queue; -+ /* used in videobuf2 callback */ -+ spinlock_t lock; -+ /* used to access capture device */ -+ struct mutex mutex; -+ /* used to wait ppi to complete one transfer */ -+ struct completion comp; -+ /* prepare to stop */ -+ bool stop; -+}; -+ -+struct bcap_fh { -+ struct v4l2_fh fh; -+ /* indicates whether this file handle is doing IO */ -+ bool io_allowed; -+}; -+ -+static const struct bcap_format bcap_formats[] = { -+ { -+ .desc = "YCbCr 4:2:2 Interleaved UYVY", -+ .pixelformat = V4L2_PIX_FMT_UYVY, -+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, -+ .bpp = 16, -+ }, -+ { -+ .desc = "YCbCr 4:2:2 Interleaved YUYV", -+ .pixelformat = V4L2_PIX_FMT_YUYV, -+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, -+ .bpp = 16, -+ }, -+ { -+ .desc = "RGB 565", -+ .pixelformat = V4L2_PIX_FMT_RGB565, -+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, -+ .bpp = 16, -+ }, -+ { -+ .desc = "RGB 444", -+ .pixelformat = V4L2_PIX_FMT_RGB444, -+ .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE, -+ .bpp = 16, -+ }, -+ -+}; -+#define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats) -+ -+static irqreturn_t bcap_isr(int irq, void *dev_id); -+ -+static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb) -+{ -+ return container_of(vb, struct bcap_buffer, vb); -+} -+ -+static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) -+{ -+ enum v4l2_mbus_pixelcode code; -+ struct bcap_format *sf; -+ unsigned int num_formats = 0; -+ int i, j; -+ -+ while (!v4l2_subdev_call(bcap_dev->sd, video, -+ enum_mbus_fmt, num_formats, &code)) -+ num_formats++; -+ if (!num_formats) -+ return -ENXIO; -+ -+ sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL); -+ if (!sf) -+ return -ENOMEM; -+ -+ for (i = 0; i < num_formats; i++) { -+ v4l2_subdev_call(bcap_dev->sd, video, -+ enum_mbus_fmt, i, &code); -+ for (j = 0; j < BCAP_MAX_FMTS; j++) -+ if (code == bcap_formats[j].mbus_code) -+ break; -+ if (j == BCAP_MAX_FMTS) { -+ /* we don't allow this sensor working with our bridge */ -+ kfree(sf); -+ return -EINVAL; -+ } -+ sf[i] = bcap_formats[j]; -+ } -+ bcap_dev->sensor_formats = sf; -+ bcap_dev->num_sensor_formats = num_formats; -+ return 0; -+} -+ -+static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) -+{ -+ bcap_dev->num_sensor_formats = 0; -+ kfree(bcap_dev->sensor_formats); -+ bcap_dev->sensor_formats = NULL; -+} -+ -+static int bcap_open(struct file *file) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct video_device *vfd = bcap_dev->video_dev; -+ struct bcap_fh *bcap_fh; -+ -+ if (!bcap_dev->sd) { -+ v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n"); -+ return -ENODEV; -+ } -+ -+ bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL); -+ if (!bcap_fh) { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "unable to allocate memory for file handle object\n"); -+ return -ENOMEM; -+ } -+ -+ v4l2_fh_init(&bcap_fh->fh, vfd); -+ -+ /* store pointer to v4l2_fh in private_data member of file */ -+ file->private_data = &bcap_fh->fh; -+ v4l2_fh_add(&bcap_fh->fh); -+ bcap_fh->io_allowed = false; -+ return 0; -+} -+ -+static int bcap_release(struct file *file) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct v4l2_fh *fh = file->private_data; -+ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); -+ -+ /* if this instance is doing IO */ -+ if (bcap_fh->io_allowed) -+ vb2_queue_release(&bcap_dev->buffer_queue); -+ -+ file->private_data = NULL; -+ v4l2_fh_del(&bcap_fh->fh); -+ v4l2_fh_exit(&bcap_fh->fh); -+ kfree(bcap_fh); -+ return 0; -+} -+ -+static int bcap_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ return vb2_mmap(&bcap_dev->buffer_queue, vma); -+} -+ -+#ifndef CONFIG_MMU -+static unsigned long bcap_get_unmapped_area(struct file *file, -+ unsigned long addr, -+ unsigned long len, -+ unsigned long pgoff, -+ unsigned long flags) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ return vb2_get_unmapped_area(&bcap_dev->buffer_queue, -+ addr, -+ len, -+ pgoff, -+ flags); -+} -+#endif -+ -+static unsigned int bcap_poll(struct file *file, poll_table *wait) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ return vb2_poll(&bcap_dev->buffer_queue, file, wait); -+} -+ -+static int bcap_queue_setup(struct vb2_queue *vq, -+ const struct v4l2_format *fmt, -+ unsigned int *nbuffers, unsigned int *nplanes, -+ unsigned int sizes[], void *alloc_ctxs[]) -+{ -+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); -+ -+ if (*nbuffers < BCAP_MIN_NUM_BUF) -+ *nbuffers = BCAP_MIN_NUM_BUF; -+ -+ *nplanes = 1; -+ sizes[0] = bcap_dev->fmt.sizeimage; -+ alloc_ctxs[0] = bcap_dev->alloc_ctx; -+ -+ return 0; -+} -+ -+static int bcap_buffer_init(struct vb2_buffer *vb) -+{ -+ struct bcap_buffer *buf = to_bcap_vb(vb); -+ -+ INIT_LIST_HEAD(&buf->list); -+ return 0; -+} -+ -+static int bcap_buffer_prepare(struct vb2_buffer *vb) -+{ -+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); -+ struct bcap_buffer *buf = to_bcap_vb(vb); -+ unsigned long size; -+ -+ size = bcap_dev->fmt.sizeimage; -+ if (vb2_plane_size(vb, 0) < size) { -+ v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", -+ vb2_plane_size(vb, 0), size); -+ return -EINVAL; -+ } -+ vb2_set_plane_payload(&buf->vb, 0, size); -+ -+ return 0; -+} -+ -+static void bcap_buffer_queue(struct vb2_buffer *vb) -+{ -+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); -+ struct bcap_buffer *buf = to_bcap_vb(vb); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&bcap_dev->lock, flags); -+ list_add_tail(&buf->list, &bcap_dev->dma_queue); -+ spin_unlock_irqrestore(&bcap_dev->lock, flags); -+} -+ -+static void bcap_buffer_cleanup(struct vb2_buffer *vb) -+{ -+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); -+ struct bcap_buffer *buf = to_bcap_vb(vb); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&bcap_dev->lock, flags); -+ list_del_init(&buf->list); -+ spin_unlock_irqrestore(&bcap_dev->lock, flags); -+} -+ -+static void bcap_lock(struct vb2_queue *vq) -+{ -+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); -+ mutex_lock(&bcap_dev->mutex); -+} -+ -+static void bcap_unlock(struct vb2_queue *vq) -+{ -+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); -+ mutex_unlock(&bcap_dev->mutex); -+} -+ -+static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) -+{ -+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); -+ struct ppi_if *ppi = bcap_dev->ppi; -+ struct ppi_params params; -+ int ret; -+ -+ /* enable streamon on the sub device */ -+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); -+ if (ret && (ret != -ENOIOCTLCMD)) { -+ v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); -+ return ret; -+ } -+ -+ /* set ppi params */ -+ params.width = bcap_dev->fmt.width; -+ params.height = bcap_dev->fmt.height; -+ params.bpp = bcap_dev->bpp; -+ params.ppi_control = bcap_dev->cfg->ppi_control; -+ params.int_mask = bcap_dev->cfg->int_mask; -+ params.blank_clocks = bcap_dev->cfg->blank_clocks; -+ ret = ppi->ops->set_params(ppi, ¶ms); -+ if (ret < 0) { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "Error in setting ppi params\n"); -+ return ret; -+ } -+ -+ /* attach ppi DMA irq handler */ -+ ret = ppi->ops->attach_irq(ppi, bcap_isr); -+ if (ret < 0) { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "Error in attaching interrupt handler\n"); -+ return ret; -+ } -+ -+ INIT_COMPLETION(bcap_dev->comp); -+ bcap_dev->stop = false; -+ return 0; -+} -+ -+static int bcap_stop_streaming(struct vb2_queue *vq) -+{ -+ struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); -+ struct ppi_if *ppi = bcap_dev->ppi; -+ int ret; -+ -+ if (!vb2_is_streaming(vq)) -+ return 0; -+ -+ bcap_dev->stop = true; -+ wait_for_completion(&bcap_dev->comp); -+ ppi->ops->stop(ppi); -+ ppi->ops->detach_irq(ppi); -+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0); -+ if (ret && (ret != -ENOIOCTLCMD)) -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "stream off failed in subdev\n"); -+ -+ /* release all active buffers */ -+ while (!list_empty(&bcap_dev->dma_queue)) { -+ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, -+ struct bcap_buffer, list); -+ list_del(&bcap_dev->next_frm->list); -+ vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR); -+ } -+ return 0; -+} -+ -+static struct vb2_ops bcap_video_qops = { -+ .queue_setup = bcap_queue_setup, -+ .buf_init = bcap_buffer_init, -+ .buf_prepare = bcap_buffer_prepare, -+ .buf_cleanup = bcap_buffer_cleanup, -+ .buf_queue = bcap_buffer_queue, -+ .wait_prepare = bcap_unlock, -+ .wait_finish = bcap_lock, -+ .start_streaming = bcap_start_streaming, -+ .stop_streaming = bcap_stop_streaming, -+}; -+ -+static int bcap_reqbufs(struct file *file, void *priv, -+ struct v4l2_requestbuffers *req_buf) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct vb2_queue *vq = &bcap_dev->buffer_queue; -+ struct v4l2_fh *fh = file->private_data; -+ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); -+ -+ if (vb2_is_busy(vq)) -+ return -EBUSY; -+ -+ bcap_fh->io_allowed = true; -+ -+ return vb2_reqbufs(vq, req_buf); -+} -+ -+static int bcap_querybuf(struct file *file, void *priv, -+ struct v4l2_buffer *buf) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ return vb2_querybuf(&bcap_dev->buffer_queue, buf); -+} -+ -+static int bcap_qbuf(struct file *file, void *priv, -+ struct v4l2_buffer *buf) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct v4l2_fh *fh = file->private_data; -+ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); -+ -+ if (!bcap_fh->io_allowed) -+ return -EBUSY; -+ -+ return vb2_qbuf(&bcap_dev->buffer_queue, buf); -+} -+ -+static int bcap_dqbuf(struct file *file, void *priv, -+ struct v4l2_buffer *buf) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct v4l2_fh *fh = file->private_data; -+ struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); -+ -+ if (!bcap_fh->io_allowed) -+ return -EBUSY; -+ -+ return vb2_dqbuf(&bcap_dev->buffer_queue, -+ buf, file->f_flags & O_NONBLOCK); -+} -+ -+static irqreturn_t bcap_isr(int irq, void *dev_id) -+{ -+ struct ppi_if *ppi = dev_id; -+ struct bcap_device *bcap_dev = ppi->priv; -+ struct timeval timevalue; -+ struct vb2_buffer *vb = &bcap_dev->cur_frm->vb; -+ dma_addr_t addr; -+ -+ spin_lock(&bcap_dev->lock); -+ -+ if (bcap_dev->cur_frm != bcap_dev->next_frm) { -+ do_gettimeofday(&timevalue); -+ vb->v4l2_buf.timestamp = timevalue; -+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE); -+ bcap_dev->cur_frm = bcap_dev->next_frm; -+ } -+ -+ ppi->ops->stop(ppi); -+ -+ if (bcap_dev->stop) { -+ complete(&bcap_dev->comp); -+ } else { -+ if (!list_empty(&bcap_dev->dma_queue)) { -+ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, -+ struct bcap_buffer, list); -+ list_del(&bcap_dev->next_frm->list); -+ addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0); -+ ppi->ops->update_addr(ppi, (unsigned long)addr); -+ } -+ ppi->ops->start(ppi); -+ } -+ -+ spin_unlock(&bcap_dev->lock); -+ -+ return IRQ_HANDLED; -+} -+ -+static int bcap_streamon(struct file *file, void *priv, -+ enum v4l2_buf_type buf_type) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct bcap_fh *fh = file->private_data; -+ struct ppi_if *ppi = bcap_dev->ppi; -+ dma_addr_t addr; -+ int ret; -+ -+ if (!fh->io_allowed) -+ return -EBUSY; -+ -+ /* call streamon to start streaming in videobuf */ -+ ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type); -+ if (ret) -+ return ret; -+ -+ /* if dma queue is empty, return error */ -+ if (list_empty(&bcap_dev->dma_queue)) { -+ v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n"); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ /* get the next frame from the dma queue */ -+ bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next, -+ struct bcap_buffer, list); -+ bcap_dev->cur_frm = bcap_dev->next_frm; -+ /* remove buffer from the dma queue */ -+ list_del(&bcap_dev->cur_frm->list); -+ addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0); -+ /* update DMA address */ -+ ppi->ops->update_addr(ppi, (unsigned long)addr); -+ /* enable ppi */ -+ ppi->ops->start(ppi); -+ -+ return 0; -+err: -+ vb2_streamoff(&bcap_dev->buffer_queue, buf_type); -+ return ret; -+} -+ -+static int bcap_streamoff(struct file *file, void *priv, -+ enum v4l2_buf_type buf_type) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct bcap_fh *fh = file->private_data; -+ -+ if (!fh->io_allowed) -+ return -EBUSY; -+ -+ return vb2_streamoff(&bcap_dev->buffer_queue, buf_type); -+} -+ -+static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); -+} -+ -+static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ *std = bcap_dev->std; -+ return 0; -+} -+ -+static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ int ret; -+ -+ if (vb2_is_busy(&bcap_dev->buffer_queue)) -+ return -EBUSY; -+ -+ ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std); -+ if (ret < 0) -+ return ret; -+ -+ bcap_dev->std = *std; -+ return 0; -+} -+ -+static int bcap_enum_input(struct file *file, void *priv, -+ struct v4l2_input *input) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct bfin_capture_config *config = bcap_dev->cfg; -+ int ret; -+ u32 status; -+ -+ if (input->index >= config->num_inputs) -+ return -EINVAL; -+ -+ *input = config->inputs[input->index]; -+ /* get input status */ -+ ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status); -+ if (!ret) -+ input->status = status; -+ return 0; -+} -+ -+static int bcap_g_input(struct file *file, void *priv, unsigned int *index) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ *index = bcap_dev->cur_input; -+ return 0; -+} -+ -+static int bcap_s_input(struct file *file, void *priv, unsigned int index) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct bfin_capture_config *config = bcap_dev->cfg; -+ struct bcap_route *route; -+ int ret; -+ -+ if (vb2_is_busy(&bcap_dev->buffer_queue)) -+ return -EBUSY; -+ -+ if (index >= config->num_inputs) -+ return -EINVAL; -+ -+ route = &config->routes[index]; -+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, -+ route->input, route->output, 0); -+ if ((ret < 0) && (ret != -ENOIOCTLCMD)) { -+ v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); -+ return ret; -+ } -+ bcap_dev->cur_input = index; -+ return 0; -+} -+ -+static int bcap_try_format(struct bcap_device *bcap, -+ struct v4l2_pix_format *pixfmt, -+ enum v4l2_mbus_pixelcode *mbus_code, -+ int *bpp) -+{ -+ struct bcap_format *sf = bcap->sensor_formats; -+ struct bcap_format *fmt = NULL; -+ struct v4l2_mbus_framefmt mbus_fmt; -+ int ret, i; -+ -+ for (i = 0; i < bcap->num_sensor_formats; i++) { -+ fmt = &sf[i]; -+ if (pixfmt->pixelformat == fmt->pixelformat) -+ break; -+ } -+ if (i == bcap->num_sensor_formats) -+ fmt = &sf[0]; -+ -+ if (mbus_code) -+ *mbus_code = fmt->mbus_code; -+ if (bpp) -+ *bpp = fmt->bpp; -+ v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code); -+ ret = v4l2_subdev_call(bcap->sd, video, -+ try_mbus_fmt, &mbus_fmt); -+ if (ret < 0) -+ return ret; -+ v4l2_fill_pix_format(pixfmt, &mbus_fmt); -+ pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8; -+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; -+ return 0; -+} -+ -+static int bcap_enum_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_fmtdesc *fmt) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct bcap_format *sf = bcap_dev->sensor_formats; -+ -+ if (fmt->index >= bcap_dev->num_sensor_formats) -+ return -EINVAL; -+ -+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ strlcpy(fmt->description, -+ sf[fmt->index].desc, -+ sizeof(fmt->description)); -+ fmt->pixelformat = sf[fmt->index].pixelformat; -+ return 0; -+} -+ -+static int bcap_try_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *fmt) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; -+ -+ return bcap_try_format(bcap_dev, pixfmt, NULL, NULL); -+} -+ -+static int bcap_g_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *fmt) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ fmt->fmt.pix = bcap_dev->fmt; -+ return 0; -+} -+ -+static int bcap_s_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *fmt) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ struct v4l2_mbus_framefmt mbus_fmt; -+ enum v4l2_mbus_pixelcode mbus_code; -+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; -+ int ret, bpp; -+ -+ if (vb2_is_busy(&bcap_dev->buffer_queue)) -+ return -EBUSY; -+ -+ /* see if format works */ -+ ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp); -+ if (ret < 0) -+ return ret; -+ -+ v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code); -+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt); -+ if (ret < 0) -+ return ret; -+ bcap_dev->fmt = *pixfmt; -+ bcap_dev->bpp = bpp; -+ return 0; -+} -+ -+static int bcap_querycap(struct file *file, void *priv, -+ struct v4l2_capability *cap) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; -+ strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); -+ strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info)); -+ strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card)); -+ return 0; -+} -+ -+static int bcap_g_parm(struct file *file, void *fh, -+ struct v4l2_streamparm *a) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a); -+} -+ -+static int bcap_s_parm(struct file *file, void *fh, -+ struct v4l2_streamparm *a) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a); -+} -+ -+static int bcap_g_chip_ident(struct file *file, void *priv, -+ struct v4l2_dbg_chip_ident *chip) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ chip->ident = V4L2_IDENT_NONE; -+ chip->revision = 0; -+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && -+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) -+ return -EINVAL; -+ -+ return v4l2_subdev_call(bcap_dev->sd, core, -+ g_chip_ident, chip); -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int bcap_dbg_g_register(struct file *file, void *priv, -+ struct v4l2_dbg_register *reg) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ return v4l2_subdev_call(bcap_dev->sd, core, -+ g_register, reg); -+} -+ -+static int bcap_dbg_s_register(struct file *file, void *priv, -+ struct v4l2_dbg_register *reg) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ -+ return v4l2_subdev_call(bcap_dev->sd, core, -+ s_register, reg); -+} -+#endif -+ -+static int bcap_log_status(struct file *file, void *priv) -+{ -+ struct bcap_device *bcap_dev = video_drvdata(file); -+ /* status for sub devices */ -+ v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status); -+ return 0; -+} -+ -+static const struct v4l2_ioctl_ops bcap_ioctl_ops = { -+ .vidioc_querycap = bcap_querycap, -+ .vidioc_g_fmt_vid_cap = bcap_g_fmt_vid_cap, -+ .vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap, -+ .vidioc_s_fmt_vid_cap = bcap_s_fmt_vid_cap, -+ .vidioc_try_fmt_vid_cap = bcap_try_fmt_vid_cap, -+ .vidioc_enum_input = bcap_enum_input, -+ .vidioc_g_input = bcap_g_input, -+ .vidioc_s_input = bcap_s_input, -+ .vidioc_querystd = bcap_querystd, -+ .vidioc_s_std = bcap_s_std, -+ .vidioc_g_std = bcap_g_std, -+ .vidioc_reqbufs = bcap_reqbufs, -+ .vidioc_querybuf = bcap_querybuf, -+ .vidioc_qbuf = bcap_qbuf, -+ .vidioc_dqbuf = bcap_dqbuf, -+ .vidioc_streamon = bcap_streamon, -+ .vidioc_streamoff = bcap_streamoff, -+ .vidioc_g_parm = bcap_g_parm, -+ .vidioc_s_parm = bcap_s_parm, -+ .vidioc_g_chip_ident = bcap_g_chip_ident, -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .vidioc_g_register = bcap_dbg_g_register, -+ .vidioc_s_register = bcap_dbg_s_register, -+#endif -+ .vidioc_log_status = bcap_log_status, -+}; -+ -+static struct v4l2_file_operations bcap_fops = { -+ .owner = THIS_MODULE, -+ .open = bcap_open, -+ .release = bcap_release, -+ .unlocked_ioctl = video_ioctl2, -+ .mmap = bcap_mmap, -+#ifndef CONFIG_MMU -+ .get_unmapped_area = bcap_get_unmapped_area, -+#endif -+ .poll = bcap_poll -+}; -+ -+static int __devinit bcap_probe(struct platform_device *pdev) -+{ -+ struct bcap_device *bcap_dev; -+ struct video_device *vfd; -+ struct i2c_adapter *i2c_adap; -+ struct bfin_capture_config *config; -+ struct vb2_queue *q; -+ int ret; -+ -+ config = pdev->dev.platform_data; -+ if (!config) { -+ v4l2_err(pdev->dev.driver, "Unable to get board config\n"); -+ return -ENODEV; -+ } -+ -+ bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL); -+ if (!bcap_dev) { -+ v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n"); -+ return -ENOMEM; -+ } -+ -+ bcap_dev->cfg = config; -+ -+ bcap_dev->ppi = ppi_create_instance(config->ppi_info); -+ if (!bcap_dev->ppi) { -+ v4l2_err(pdev->dev.driver, "Unable to create ppi\n"); -+ ret = -ENODEV; -+ goto err_free_dev; -+ } -+ bcap_dev->ppi->priv = bcap_dev; -+ -+ bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); -+ if (IS_ERR(bcap_dev->alloc_ctx)) { -+ ret = PTR_ERR(bcap_dev->alloc_ctx); -+ goto err_free_ppi; -+ } -+ -+ vfd = video_device_alloc(); -+ if (!vfd) { -+ ret = -ENOMEM; -+ v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); -+ goto err_cleanup_ctx; -+ } -+ -+ /* initialize field of video device */ -+ vfd->release = video_device_release; -+ vfd->fops = &bcap_fops; -+ vfd->ioctl_ops = &bcap_ioctl_ops; -+ vfd->tvnorms = 0; -+ vfd->v4l2_dev = &bcap_dev->v4l2_dev; -+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); -+ strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); -+ bcap_dev->video_dev = vfd; -+ -+ ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); -+ if (ret) { -+ v4l2_err(pdev->dev.driver, -+ "Unable to register v4l2 device\n"); -+ goto err_release_vdev; -+ } -+ v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); -+ -+ bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler; -+ ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0); -+ if (ret) { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "Unable to init control handler\n"); -+ goto err_unreg_v4l2; -+ } -+ -+ spin_lock_init(&bcap_dev->lock); -+ /* initialize queue */ -+ q = &bcap_dev->buffer_queue; -+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ q->io_modes = VB2_MMAP; -+ q->drv_priv = bcap_dev; -+ q->buf_struct_size = sizeof(struct bcap_buffer); -+ q->ops = &bcap_video_qops; -+ q->mem_ops = &vb2_dma_contig_memops; -+ -+ vb2_queue_init(q); -+ -+ mutex_init(&bcap_dev->mutex); -+ init_completion(&bcap_dev->comp); -+ -+ /* init video dma queues */ -+ INIT_LIST_HEAD(&bcap_dev->dma_queue); -+ -+ vfd->lock = &bcap_dev->mutex; -+ -+ /* register video device */ -+ ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); -+ if (ret) { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "Unable to register video device\n"); -+ goto err_free_handler; -+ } -+ video_set_drvdata(bcap_dev->video_dev, bcap_dev); -+ v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", -+ video_device_node_name(vfd)); -+ -+ /* load up the subdevice */ -+ i2c_adap = i2c_get_adapter(config->i2c_adapter_id); -+ if (!i2c_adap) { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "Unable to find i2c adapter\n"); -+ goto err_unreg_vdev; -+ -+ } -+ bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev, -+ i2c_adap, -+ &config->board_info, -+ NULL); -+ if (bcap_dev->sd) { -+ int i; -+ /* update tvnorms from the sub devices */ -+ for (i = 0; i < config->num_inputs; i++) -+ vfd->tvnorms |= config->inputs[i].std; -+ } else { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "Unable to register sub device\n"); -+ goto err_unreg_vdev; -+ } -+ -+ v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n"); -+ -+ /* now we can probe the default state */ -+ if (vfd->tvnorms) { -+ v4l2_std_id std; -+ ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std); -+ if (ret) { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "Unable to get std\n"); -+ goto err_unreg_vdev; -+ } -+ bcap_dev->std = std; -+ } -+ ret = bcap_init_sensor_formats(bcap_dev); -+ if (ret) { -+ v4l2_err(&bcap_dev->v4l2_dev, -+ "Unable to create sensor formats table\n"); -+ goto err_unreg_vdev; -+ } -+ return 0; -+err_unreg_vdev: -+ video_unregister_device(bcap_dev->video_dev); -+ bcap_dev->video_dev = NULL; -+err_free_handler: -+ v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); -+err_unreg_v4l2: -+ v4l2_device_unregister(&bcap_dev->v4l2_dev); -+err_release_vdev: -+ if (bcap_dev->video_dev) -+ video_device_release(bcap_dev->video_dev); -+err_cleanup_ctx: -+ vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); -+err_free_ppi: -+ ppi_delete_instance(bcap_dev->ppi); -+err_free_dev: -+ kfree(bcap_dev); -+ return ret; -+} -+ -+static int __devexit bcap_remove(struct platform_device *pdev) -+{ -+ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); -+ struct bcap_device *bcap_dev = container_of(v4l2_dev, -+ struct bcap_device, v4l2_dev); -+ -+ bcap_free_sensor_formats(bcap_dev); -+ video_unregister_device(bcap_dev->video_dev); -+ v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); -+ v4l2_device_unregister(v4l2_dev); -+ vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); -+ ppi_delete_instance(bcap_dev->ppi); -+ kfree(bcap_dev); -+ return 0; -+} -+ -+static struct platform_driver bcap_driver = { -+ .driver = { -+ .name = CAPTURE_DRV_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .probe = bcap_probe, -+ .remove = __devexit_p(bcap_remove), -+}; -+ -+static __init int bcap_init(void) -+{ -+ return platform_driver_register(&bcap_driver); -+} -+ -+static __exit void bcap_exit(void) -+{ -+ platform_driver_unregister(&bcap_driver); -+} -+ -+module_init(bcap_init); -+module_exit(bcap_exit); -+ -+MODULE_DESCRIPTION("Analog Devices blackfin video capture driver"); -+MODULE_AUTHOR("Scott Jiang "); -+MODULE_LICENSE("GPL v2"); -Index: linux-3.3.x86_64/drivers/media/video/blackfin/ppi.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/blackfin/ppi.c -@@ -0,0 +1,271 @@ -+/* -+ * ppi.c Analog Devices Parallel Peripheral Interface driver -+ * -+ * Copyright (c) 2011 Analog Devices Inc. -+ * -+ * 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. -+ * -+ * 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 -+ -+#include -+ -+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler); -+static void ppi_detach_irq(struct ppi_if *ppi); -+static int ppi_start(struct ppi_if *ppi); -+static int ppi_stop(struct ppi_if *ppi); -+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params); -+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr); -+ -+static const struct ppi_ops ppi_ops = { -+ .attach_irq = ppi_attach_irq, -+ .detach_irq = ppi_detach_irq, -+ .start = ppi_start, -+ .stop = ppi_stop, -+ .set_params = ppi_set_params, -+ .update_addr = ppi_update_addr, -+}; -+ -+static irqreturn_t ppi_irq_err(int irq, void *dev_id) -+{ -+ struct ppi_if *ppi = dev_id; -+ const struct ppi_info *info = ppi->info; -+ -+ switch (info->type) { -+ case PPI_TYPE_PPI: -+ { -+ struct bfin_ppi_regs *reg = info->base; -+ unsigned short status; -+ -+ /* register on bf561 is cleared when read -+ * others are W1C -+ */ -+ status = bfin_read16(®->status); -+ bfin_write16(®->status, 0xff00); -+ break; -+ } -+ case PPI_TYPE_EPPI: -+ { -+ struct bfin_eppi_regs *reg = info->base; -+ bfin_write16(®->status, 0xffff); -+ break; -+ } -+ default: -+ break; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler) -+{ -+ const struct ppi_info *info = ppi->info; -+ int ret; -+ -+ ret = request_dma(info->dma_ch, "PPI_DMA"); -+ -+ if (ret) { -+ pr_err("Unable to allocate DMA channel for PPI\n"); -+ return ret; -+ } -+ set_dma_callback(info->dma_ch, handler, ppi); -+ -+ if (ppi->err_int) { -+ ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi); -+ if (ret) { -+ pr_err("Unable to allocate IRQ for PPI\n"); -+ free_dma(info->dma_ch); -+ } -+ } -+ return ret; -+} -+ -+static void ppi_detach_irq(struct ppi_if *ppi) -+{ -+ const struct ppi_info *info = ppi->info; -+ -+ if (ppi->err_int) -+ free_irq(info->irq_err, ppi); -+ free_dma(info->dma_ch); -+} -+ -+static int ppi_start(struct ppi_if *ppi) -+{ -+ const struct ppi_info *info = ppi->info; -+ -+ /* enable DMA */ -+ enable_dma(info->dma_ch); -+ -+ /* enable PPI */ -+ ppi->ppi_control |= PORT_EN; -+ switch (info->type) { -+ case PPI_TYPE_PPI: -+ { -+ struct bfin_ppi_regs *reg = info->base; -+ bfin_write16(®->control, ppi->ppi_control); -+ break; -+ } -+ case PPI_TYPE_EPPI: -+ { -+ struct bfin_eppi_regs *reg = info->base; -+ bfin_write32(®->control, ppi->ppi_control); -+ break; -+ } -+ default: -+ return -EINVAL; -+ } -+ -+ SSYNC(); -+ return 0; -+} -+ -+static int ppi_stop(struct ppi_if *ppi) -+{ -+ const struct ppi_info *info = ppi->info; -+ -+ /* disable PPI */ -+ ppi->ppi_control &= ~PORT_EN; -+ switch (info->type) { -+ case PPI_TYPE_PPI: -+ { -+ struct bfin_ppi_regs *reg = info->base; -+ bfin_write16(®->control, ppi->ppi_control); -+ break; -+ } -+ case PPI_TYPE_EPPI: -+ { -+ struct bfin_eppi_regs *reg = info->base; -+ bfin_write32(®->control, ppi->ppi_control); -+ break; -+ } -+ default: -+ return -EINVAL; -+ } -+ -+ /* disable DMA */ -+ clear_dma_irqstat(info->dma_ch); -+ disable_dma(info->dma_ch); -+ -+ SSYNC(); -+ return 0; -+} -+ -+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) -+{ -+ const struct ppi_info *info = ppi->info; -+ int dma32 = 0; -+ int dma_config, bytes_per_line, lines_per_frame; -+ -+ bytes_per_line = params->width * params->bpp / 8; -+ lines_per_frame = params->height; -+ if (params->int_mask == 0xFFFFFFFF) -+ ppi->err_int = false; -+ else -+ ppi->err_int = true; -+ -+ dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN); -+ ppi->ppi_control = params->ppi_control & ~PORT_EN; -+ switch (info->type) { -+ case PPI_TYPE_PPI: -+ { -+ struct bfin_ppi_regs *reg = info->base; -+ -+ if (params->ppi_control & DMA32) -+ dma32 = 1; -+ -+ bfin_write16(®->control, ppi->ppi_control); -+ bfin_write16(®->count, bytes_per_line - 1); -+ bfin_write16(®->frame, lines_per_frame); -+ break; -+ } -+ case PPI_TYPE_EPPI: -+ { -+ struct bfin_eppi_regs *reg = info->base; -+ -+ if ((params->ppi_control & PACK_EN) -+ || (params->ppi_control & 0x38000) > DLEN_16) -+ dma32 = 1; -+ -+ bfin_write32(®->control, ppi->ppi_control); -+ bfin_write16(®->line, bytes_per_line + params->blank_clocks); -+ bfin_write16(®->frame, lines_per_frame); -+ bfin_write16(®->hdelay, 0); -+ bfin_write16(®->vdelay, 0); -+ bfin_write16(®->hcount, bytes_per_line); -+ bfin_write16(®->vcount, lines_per_frame); -+ break; -+ } -+ default: -+ return -EINVAL; -+ } -+ -+ if (dma32) { -+ dma_config |= WDSIZE_32; -+ set_dma_x_count(info->dma_ch, bytes_per_line >> 2); -+ set_dma_x_modify(info->dma_ch, 4); -+ set_dma_y_modify(info->dma_ch, 4); -+ } else { -+ dma_config |= WDSIZE_16; -+ set_dma_x_count(info->dma_ch, bytes_per_line >> 1); -+ set_dma_x_modify(info->dma_ch, 2); -+ set_dma_y_modify(info->dma_ch, 2); -+ } -+ set_dma_y_count(info->dma_ch, lines_per_frame); -+ set_dma_config(info->dma_ch, dma_config); -+ -+ SSYNC(); -+ return 0; -+} -+ -+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr) -+{ -+ set_dma_start_addr(ppi->info->dma_ch, addr); -+} -+ -+struct ppi_if *ppi_create_instance(const struct ppi_info *info) -+{ -+ struct ppi_if *ppi; -+ -+ if (!info || !info->pin_req) -+ return NULL; -+ -+ if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) { -+ pr_err("request peripheral failed\n"); -+ return NULL; -+ } -+ -+ ppi = kzalloc(sizeof(*ppi), GFP_KERNEL); -+ if (!ppi) { -+ peripheral_free_list(info->pin_req); -+ pr_err("unable to allocate memory for ppi handle\n"); -+ return NULL; -+ } -+ ppi->ops = &ppi_ops; -+ ppi->info = info; -+ -+ pr_info("ppi probe success\n"); -+ return ppi; -+} -+ -+void ppi_delete_instance(struct ppi_if *ppi) -+{ -+ peripheral_free_list(ppi->info->pin_req); -+ kfree(ppi); -+} -Index: linux-3.3.x86_64/include/media/blackfin/bfin_capture.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/include/media/blackfin/bfin_capture.h -@@ -0,0 +1,37 @@ -+#ifndef _BFIN_CAPTURE_H_ -+#define _BFIN_CAPTURE_H_ -+ -+#include -+ -+struct v4l2_input; -+struct ppi_info; -+ -+struct bcap_route { -+ u32 input; -+ u32 output; -+}; -+ -+struct bfin_capture_config { -+ /* card name */ -+ char *card_name; -+ /* inputs available at the sub device */ -+ struct v4l2_input *inputs; -+ /* number of inputs supported */ -+ int num_inputs; -+ /* routing information for each input */ -+ struct bcap_route *routes; -+ /* i2c bus adapter no */ -+ int i2c_adapter_id; -+ /* i2c subdevice board info */ -+ struct i2c_board_info board_info; -+ /* ppi board info */ -+ const struct ppi_info *ppi_info; -+ /* ppi control */ -+ unsigned long ppi_control; -+ /* ppi interrupt mask */ -+ u32 int_mask; -+ /* horizontal blanking clocks */ -+ int blank_clocks; -+}; -+ -+#endif -Index: linux-3.3.x86_64/include/media/blackfin/ppi.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/include/media/blackfin/ppi.h -@@ -0,0 +1,74 @@ -+/* -+ * Analog Devices PPI header file -+ * -+ * Copyright (c) 2011 Analog Devices Inc. -+ * -+ * 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. -+ * -+ * 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 _PPI_H_ -+#define _PPI_H_ -+ -+#include -+ -+#ifdef EPPI_EN -+#define PORT_EN EPPI_EN -+#define DMA32 0 -+#define PACK_EN PACKEN -+#endif -+ -+struct ppi_if; -+ -+struct ppi_params { -+ int width; -+ int height; -+ int bpp; -+ unsigned long ppi_control; -+ u32 int_mask; -+ int blank_clocks; -+}; -+ -+struct ppi_ops { -+ int (*attach_irq)(struct ppi_if *ppi, irq_handler_t handler); -+ void (*detach_irq)(struct ppi_if *ppi); -+ int (*start)(struct ppi_if *ppi); -+ int (*stop)(struct ppi_if *ppi); -+ int (*set_params)(struct ppi_if *ppi, struct ppi_params *params); -+ void (*update_addr)(struct ppi_if *ppi, unsigned long addr); -+}; -+ -+enum ppi_type { -+ PPI_TYPE_PPI, -+ PPI_TYPE_EPPI, -+}; -+ -+struct ppi_info { -+ enum ppi_type type; -+ int dma_ch; -+ int irq_err; -+ void __iomem *base; -+ const unsigned short *pin_req; -+}; -+ -+struct ppi_if { -+ unsigned long ppi_control; -+ const struct ppi_ops *ops; -+ const struct ppi_info *info; -+ bool err_int; -+ void *priv; -+}; -+ -+struct ppi_if *ppi_create_instance(const struct ppi_info *info); -+void ppi_delete_instance(struct ppi_if *ppi); -+#endif -Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/selection-api.xml -=================================================================== ---- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/selection-api.xml -+++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/selection-api.xml -@@ -52,6 +52,10 @@ cropping and composing rectangles have t - - - -+ -+For complete list of the available selection targets see table -+ - - -
-@@ -186,7 +190,7 @@ V4L2_SEL_TGT_COMPOSE_ACTIVE - -
- -- Scaling control. -+ Scaling control - - An application can detect if scaling is performed by comparing the width - and the height of rectangles obtained using V4L2_SEL_TGT_CROP_ACTIVE -@@ -200,7 +204,7 @@ the scaling ratios using these values. - -- Comparison with old cropping API. -+ Comparison with old cropping API - - The selection API was introduced to cope with deficiencies of previous - API , that was designed to control simple capture -Index: linux-3.3.x86_64/Documentation/DocBook/media/v4l/vidioc-g-selection.xml -=================================================================== ---- linux-3.3.x86_64.orig/Documentation/DocBook/media/v4l/vidioc-g-selection.xml -+++ linux-3.3.x86_64/Documentation/DocBook/media/v4l/vidioc-g-selection.xml -@@ -58,43 +58,43 @@ - - The ioctls are used to query and configure selection rectangles. - -- To query the cropping (composing) rectangle set --&v4l2-selection;::type to the respective buffer type. Do not --use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE -+ To query the cropping (composing) rectangle set &v4l2-selection; -+ type field to the respective buffer type. -+Do not use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE - instead of V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE - . Use V4L2_BUF_TYPE_VIDEO_OUTPUT instead of - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE . The next step is --setting &v4l2-selection;::target to value -- V4L2_SEL_TGT_CROP_ACTIVE ( -+setting the value of &v4l2-selection; target field -+to V4L2_SEL_TGT_CROP_ACTIVE ( - V4L2_SEL_TGT_COMPOSE_ACTIVE ). Please refer to table or for additional --targets. Fields &v4l2-selection;::flags and -- &v4l2-selection;::reserved are ignored and they --must be filled with zeros. The driver fills the rest of the structure or -+targets. The flags and reserved -+ fields of &v4l2-selection; are ignored and they must be filled -+with zeros. The driver fills the rest of the structure or - returns &EINVAL; if incorrect buffer type or target was used. If cropping - (composing) is not supported then the active rectangle is not mutable and it is --always equal to the bounds rectangle. Finally, structure --&v4l2-selection;::r is filled with the current cropping -+always equal to the bounds rectangle. Finally, the &v4l2-rect; -+r rectangle is filled with the current cropping - (composing) coordinates. The coordinates are expressed in driver-dependent - units. The only exception are rectangles for images in raw formats, whose - coordinates are always expressed in pixels. - -- To change the cropping (composing) rectangle set --&v4l2-selection;::type to the respective buffer type. Do not -+ To change the cropping (composing) rectangle set the &v4l2-selection; -+type field to the respective buffer type. Do not - use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE - instead of V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE - . Use V4L2_BUF_TYPE_VIDEO_OUTPUT instead of - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE . The next step is --setting &v4l2-selection;::target to value -- V4L2_SEL_TGT_CROP_ACTIVE ( -+setting the value of &v4l2-selection; target to -+V4L2_SEL_TGT_CROP_ACTIVE ( - V4L2_SEL_TGT_COMPOSE_ACTIVE ). Please refer to table or for additional --targets. Set desired active area into the field --&v4l2-selection;::r . Field --&v4l2-selection;::reserved is ignored and must be filled with --zeros. The driver may adjust the rectangle coordinates. An application may --introduce constraints to control rounding behaviour. Set the field -- &v4l2-selection;::flags to one of values: -+targets. The &v4l2-rect; r rectangle need to be -+set to the desired active area. Field &v4l2-selection; reserved -+ is ignored and must be filled with zeros. The driver may adjust -+coordinates of the requested rectangle. An application may -+introduce constraints to control rounding behaviour. The &v4l2-selection; -+flags field must be set to one of the following: - - - -@@ -129,7 +129,7 @@ and vertical offset and sizes are chosen - - - -- Satisfy constraints from &v4l2-selection;::flags. -+ Satisfy constraints from &v4l2-selection; flags. - - - Adjust width, height, left, and top to hardware limits and alignments. -@@ -145,7 +145,7 @@ and vertical offset and sizes are chosen - - - --On success the field &v4l2-selection;::r contains -+On success the &v4l2-rect; r field contains - the adjusted rectangle. When the parameters are unsuitable the application may - modify the cropping (composing) or image parameters and repeat the cycle until - satisfactory parameters have been negotiated. If constraints flags have to be -@@ -162,38 +162,38 @@ exist no rectangle that sati - - - V4L2_SEL_TGT_CROP_ACTIVE -- 0 -- area that is currently cropped by hardware -+ 0x0000 -+ The area that is currently cropped by hardware. - - - V4L2_SEL_TGT_CROP_DEFAULT -- 1 -- suggested cropping rectangle that covers the "whole picture" -+ 0x0001 -+ Suggested cropping rectangle that covers the "whole picture". - - - V4L2_SEL_TGT_CROP_BOUNDS -- 2 -- limits for the cropping rectangle -+ 0x0002 -+ Limits for the cropping rectangle. - - - V4L2_SEL_TGT_COMPOSE_ACTIVE -- 256 -- area to which data are composed by hardware -+ 0x0100 -+ The area to which data is composed by hardware. - - - V4L2_SEL_TGT_COMPOSE_DEFAULT -- 257 -- suggested composing rectangle that covers the "whole picture" -+ 0x0101 -+ Suggested composing rectangle that covers the "whole picture". - - - V4L2_SEL_TGT_COMPOSE_BOUNDS -- 258 -- limits for the composing rectangle -+ 0x0102 -+ Limits for the composing rectangle. - - - V4L2_SEL_TGT_COMPOSE_PADDED -- 259 -- the active area and all padding pixels that are inserted or modified by the hardware -+ 0x0103 -+ The active area and all padding pixels that are inserted or modified by hardware. - - - -@@ -209,12 +209,14 @@ exist no rectangle that sati - - V4L2_SEL_FLAG_GE - 0x00000001 -- indicate that adjusted rectangle must contain a rectangle from &v4l2-selection;::r -+ Indicates that the adjusted rectangle must contain the original -+ &v4l2-selection; r rectangle. - - - V4L2_SEL_FLAG_LE - 0x00000002 -- indicate that adjusted rectangle must be inside a rectangle from &v4l2-selection;::r -+ Indicates that the adjusted rectangle must be inside the original -+ &v4l2-rect; r rectangle. - - - -@@ -245,27 +247,29 @@ exist no rectangle that sati - - __u32 - type -- Type of the buffer (from &v4l2-buf-type;) -+ Type of the buffer (from &v4l2-buf-type;). - - - __u32 - target -- used to select between cropping and composing rectangles -+ Used to select between cropping -+ and composing rectangles. - - - __u32 - flags -- control over coordinates adjustments, refer to selection flags -+ Flags controlling the selection rectangle adjustments, refer to -+ selection flags. - - - &v4l2-rect; - r -- selection rectangle -+ The selection rectangle. - - - __u32 - reserved[9] -- Reserved fields for future use -+ Reserved fields for future use. - - - -@@ -278,24 +282,24 @@ exist no rectangle that sati - - EINVAL - -- The buffer &v4l2-selection;::type --or &v4l2-selection;::target is not supported, or --the &v4l2-selection;::flags are invalid. -+ Given buffer type type or -+the selection target target is not supported, -+or the flags argument is not valid. - - - - ERANGE - -- it is not possible to adjust a rectangle --&v4l2-selection;::r that satisfies all contraints from -- &v4l2-selection;::flags . -+ It is not possible to adjust &v4l2-rect; -+r rectangle to satisfy all contraints given in the -+flags argument. - - - - EBUSY - -- it is not possible to apply change of selection rectangle at the moment. --Usually because streaming is in progress. -+ It is not possible to apply change of the selection rectangle -+at the moment. Usually because streaming is in progress. - - - -Index: linux-3.3.x86_64/drivers/media/video/w9966.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/w9966.c -+++ linux-3.3.x86_64/drivers/media/video/w9966.c -@@ -129,9 +129,9 @@ MODULE_LICENSE("GPL"); - MODULE_VERSION("0.33.1"); - - #ifdef MODULE --static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; -+static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; - #else --static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; -+static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; - #endif - module_param_array(pardev, charp, NULL, 0); - MODULE_PARM_DESC(pardev, "pardev: where to search for\n" -Index: linux-3.3.x86_64/drivers/media/dvb/pt1/pt1.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/pt1/pt1.c -+++ linux-3.3.x86_64/drivers/media/dvb/pt1/pt1.c -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - - #include "dvbdev.h" - #include "dvb_demux.h" -@@ -77,6 +78,8 @@ struct pt1 { - struct pt1_adapter *adaps[PT1_NR_ADAPS]; - struct pt1_table *tables; - struct task_struct *kthread; -+ int table_index; -+ int buf_index; - - struct mutex lock; - int power; -@@ -90,12 +93,12 @@ struct pt1_adapter { - u8 *buf; - int upacket_count; - int packet_count; -+ int st_count; - - struct dvb_adapter adap; - struct dvb_demux demux; - int users; - struct dmxdev dmxdev; -- struct dvb_net net; - struct dvb_frontend *fe; - int (*orig_set_voltage)(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); -@@ -119,7 +122,7 @@ static u32 pt1_read_reg(struct pt1 *pt1, - return readl(pt1->regs + reg * 4); - } - --static int pt1_nr_tables = 64; -+static int pt1_nr_tables = 8; - module_param_named(nr_tables, pt1_nr_tables, int, 0); - - static void pt1_increment_table_count(struct pt1 *pt1) -@@ -264,6 +267,7 @@ static int pt1_filter(struct pt1 *pt1, s - struct pt1_adapter *adap; - int offset; - u8 *buf; -+ int sc; - - if (!page->upackets[PT1_NR_UPACKETS - 1]) - return 0; -@@ -280,6 +284,16 @@ static int pt1_filter(struct pt1 *pt1, s - else if (!adap->upacket_count) - continue; - -+ if (upacket >> 24 & 1) -+ printk_ratelimited(KERN_INFO "earth-pt1: device " -+ "buffer overflowing. table[%d] buf[%d]\n", -+ pt1->table_index, pt1->buf_index); -+ sc = upacket >> 26 & 0x7; -+ if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7)) -+ printk_ratelimited(KERN_INFO "earth-pt1: data loss" -+ " in streamID(adapter)[%d]\n", index); -+ adap->st_count = sc; -+ - buf = adap->buf; - offset = adap->packet_count * 188 + adap->upacket_count * 3; - buf[offset] = upacket >> 16; -@@ -303,30 +317,25 @@ static int pt1_filter(struct pt1 *pt1, s - static int pt1_thread(void *data) - { - struct pt1 *pt1; -- int table_index; -- int buf_index; - struct pt1_buffer_page *page; - - pt1 = data; - set_freezable(); - -- table_index = 0; -- buf_index = 0; -- - while (!kthread_should_stop()) { - try_to_freeze(); - -- page = pt1->tables[table_index].bufs[buf_index].page; -+ page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page; - if (!pt1_filter(pt1, page)) { - schedule_timeout_interruptible((HZ + 999) / 1000); - continue; - } - -- if (++buf_index >= PT1_NR_BUFS) { -+ if (++pt1->buf_index >= PT1_NR_BUFS) { - pt1_increment_table_count(pt1); -- buf_index = 0; -- if (++table_index >= pt1_nr_tables) -- table_index = 0; -+ pt1->buf_index = 0; -+ if (++pt1->table_index >= pt1_nr_tables) -+ pt1->table_index = 0; - } - } - -@@ -477,21 +486,60 @@ err: - return ret; - } - -+static int pt1_start_polling(struct pt1 *pt1) -+{ -+ int ret = 0; -+ -+ mutex_lock(&pt1->lock); -+ if (!pt1->kthread) { -+ pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1"); -+ if (IS_ERR(pt1->kthread)) { -+ ret = PTR_ERR(pt1->kthread); -+ pt1->kthread = NULL; -+ } -+ } -+ mutex_unlock(&pt1->lock); -+ return ret; -+} -+ - static int pt1_start_feed(struct dvb_demux_feed *feed) - { - struct pt1_adapter *adap; - adap = container_of(feed->demux, struct pt1_adapter, demux); -- if (!adap->users++) -+ if (!adap->users++) { -+ int ret; -+ -+ ret = pt1_start_polling(adap->pt1); -+ if (ret) -+ return ret; - pt1_set_stream(adap->pt1, adap->index, 1); -+ } - return 0; - } - -+static void pt1_stop_polling(struct pt1 *pt1) -+{ -+ int i, count; -+ -+ mutex_lock(&pt1->lock); -+ for (i = 0, count = 0; i < PT1_NR_ADAPS; i++) -+ count += pt1->adaps[i]->users; -+ -+ if (count == 0 && pt1->kthread) { -+ kthread_stop(pt1->kthread); -+ pt1->kthread = NULL; -+ } -+ mutex_unlock(&pt1->lock); -+} -+ - static int pt1_stop_feed(struct dvb_demux_feed *feed) - { - struct pt1_adapter *adap; - adap = container_of(feed->demux, struct pt1_adapter, demux); -- if (!--adap->users) -+ if (!--adap->users) { - pt1_set_stream(adap->pt1, adap->index, 0); -+ pt1_stop_polling(adap->pt1); -+ } - return 0; - } - -@@ -575,7 +623,6 @@ static int pt1_wakeup(struct dvb_fronten - - static void pt1_free_adapter(struct pt1_adapter *adap) - { -- dvb_net_release(&adap->net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); -@@ -616,6 +663,7 @@ pt1_alloc_adapter(struct pt1 *pt1) - adap->buf = buf; - adap->upacket_count = 0; - adap->packet_count = 0; -+ adap->st_count = -1; - - dvb_adap = &adap->adap; - dvb_adap->priv = adap; -@@ -644,8 +692,6 @@ pt1_alloc_adapter(struct pt1 *pt1) - if (ret < 0) - goto err_dmx_release; - -- dvb_net_init(dvb_adap, &adap->net, &demux->dmx); -- - return adap; - - err_dmx_release: -@@ -1020,7 +1066,8 @@ static void __devexit pt1_remove(struct - pt1 = pci_get_drvdata(pdev); - regs = pt1->regs; - -- kthread_stop(pt1->kthread); -+ if (pt1->kthread) -+ kthread_stop(pt1->kthread); - pt1_cleanup_tables(pt1); - pt1_cleanup_frontends(pt1); - pt1_disable_ram(pt1); -@@ -1043,7 +1090,6 @@ pt1_probe(struct pci_dev *pdev, const st - void __iomem *regs; - struct pt1 *pt1; - struct i2c_adapter *i2c_adap; -- struct task_struct *kthread; - - ret = pci_enable_device(pdev); - if (ret < 0) -@@ -1139,17 +1185,8 @@ pt1_probe(struct pci_dev *pdev, const st - if (ret < 0) - goto err_pt1_cleanup_frontends; - -- kthread = kthread_run(pt1_thread, pt1, "pt1"); -- if (IS_ERR(kthread)) { -- ret = PTR_ERR(kthread); -- goto err_pt1_cleanup_tables; -- } -- -- pt1->kthread = kthread; - return 0; - --err_pt1_cleanup_tables: -- pt1_cleanup_tables(pt1); - err_pt1_cleanup_frontends: - pt1_cleanup_frontends(pt1); - err_pt1_disable_ram: -Index: linux-3.3.x86_64/drivers/media/video/aptina-pll.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/aptina-pll.c -@@ -0,0 +1,174 @@ -+/* -+ * Aptina Sensor PLL Configuration -+ * -+ * Copyright (C) 2012 Laurent Pinchart -+ * -+ * 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. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "aptina-pll.h" -+ -+int aptina_pll_calculate(struct device *dev, -+ const struct aptina_pll_limits *limits, -+ struct aptina_pll *pll) -+{ -+ unsigned int mf_min; -+ unsigned int mf_max; -+ unsigned int p1_min; -+ unsigned int p1_max; -+ unsigned int p1; -+ unsigned int div; -+ -+ dev_dbg(dev, "PLL: ext clock %u pix clock %u\n", -+ pll->ext_clock, pll->pix_clock); -+ -+ if (pll->ext_clock < limits->ext_clock_min || -+ pll->ext_clock > limits->ext_clock_max) { -+ dev_err(dev, "pll: invalid external clock frequency.\n"); -+ return -EINVAL; -+ } -+ -+ if (pll->pix_clock == 0 || pll->pix_clock > limits->pix_clock_max) { -+ dev_err(dev, "pll: invalid pixel clock frequency.\n"); -+ return -EINVAL; -+ } -+ -+ /* Compute the multiplier M and combined N*P1 divisor. */ -+ div = gcd(pll->pix_clock, pll->ext_clock); -+ pll->m = pll->pix_clock / div; -+ div = pll->ext_clock / div; -+ -+ /* We now have the smallest M and N*P1 values that will result in the -+ * desired pixel clock frequency, but they might be out of the valid -+ * range. Compute the factor by which we should multiply them given the -+ * following constraints: -+ * -+ * - minimum/maximum multiplier -+ * - minimum/maximum multiplier output clock frequency assuming the -+ * minimum/maximum N value -+ * - minimum/maximum combined N*P1 divisor -+ */ -+ mf_min = DIV_ROUND_UP(limits->m_min, pll->m); -+ mf_min = max(mf_min, limits->out_clock_min / -+ (pll->ext_clock / limits->n_min * pll->m)); -+ mf_min = max(mf_min, limits->n_min * limits->p1_min / div); -+ mf_max = limits->m_max / pll->m; -+ mf_max = min(mf_max, limits->out_clock_max / -+ (pll->ext_clock / limits->n_max * pll->m)); -+ mf_max = min(mf_max, DIV_ROUND_UP(limits->n_max * limits->p1_max, div)); -+ -+ dev_dbg(dev, "pll: mf min %u max %u\n", mf_min, mf_max); -+ if (mf_min > mf_max) { -+ dev_err(dev, "pll: no valid combined N*P1 divisor.\n"); -+ return -EINVAL; -+ } -+ -+ /* -+ * We're looking for the highest acceptable P1 value for which a -+ * multiplier factor MF exists that fulfills the following conditions: -+ * -+ * 1. p1 is in the [p1_min, p1_max] range given by the limits and is -+ * even -+ * 2. mf is in the [mf_min, mf_max] range computed above -+ * 3. div * mf is a multiple of p1, in order to compute -+ * n = div * mf / p1 -+ * m = pll->m * mf -+ * 4. the internal clock frequency, given by ext_clock / n, is in the -+ * [int_clock_min, int_clock_max] range given by the limits -+ * 5. the output clock frequency, given by ext_clock / n * m, is in the -+ * [out_clock_min, out_clock_max] range given by the limits -+ * -+ * The first naive approach is to iterate over all p1 values acceptable -+ * according to (1) and all mf values acceptable according to (2), and -+ * stop at the first combination that fulfills (3), (4) and (5). This -+ * has a O(n^2) complexity. -+ * -+ * Instead of iterating over all mf values in the [mf_min, mf_max] range -+ * we can compute the mf increment between two acceptable values -+ * according to (3) with -+ * -+ * mf_inc = p1 / gcd(div, p1) (6) -+ * -+ * and round the minimum up to the nearest multiple of mf_inc. This will -+ * restrict the number of mf values to be checked. -+ * -+ * Furthermore, conditions (4) and (5) only restrict the range of -+ * acceptable p1 and mf values by modifying the minimum and maximum -+ * limits. (5) can be expressed as -+ * -+ * ext_clock / (div * mf / p1) * m * mf >= out_clock_min -+ * ext_clock / (div * mf / p1) * m * mf <= out_clock_max -+ * -+ * or -+ * -+ * p1 >= out_clock_min * div / (ext_clock * m) (7) -+ * p1 <= out_clock_max * div / (ext_clock * m) -+ * -+ * Similarly, (4) can be expressed as -+ * -+ * mf >= ext_clock * p1 / (int_clock_max * div) (8) -+ * mf <= ext_clock * p1 / (int_clock_min * div) -+ * -+ * We can thus iterate over the restricted p1 range defined by the -+ * combination of (1) and (7), and then compute the restricted mf range -+ * defined by the combination of (2), (6) and (8). If the resulting mf -+ * range is not empty, any value in the mf range is acceptable. We thus -+ * select the mf lwoer bound and the corresponding p1 value. -+ */ -+ if (limits->p1_min == 0) { -+ dev_err(dev, "pll: P1 minimum value must be >0.\n"); -+ return -EINVAL; -+ } -+ -+ p1_min = max(limits->p1_min, DIV_ROUND_UP(limits->out_clock_min * div, -+ pll->ext_clock * pll->m)); -+ p1_max = min(limits->p1_max, limits->out_clock_max * div / -+ (pll->ext_clock * pll->m)); -+ -+ for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) { -+ unsigned int mf_inc = p1 / gcd(div, p1); -+ unsigned int mf_high; -+ unsigned int mf_low; -+ -+ mf_low = max(roundup(mf_min, mf_inc), -+ DIV_ROUND_UP(pll->ext_clock * p1, -+ limits->int_clock_max * div)); -+ mf_high = min(mf_max, pll->ext_clock * p1 / -+ (limits->int_clock_min * div)); -+ -+ if (mf_low > mf_high) -+ continue; -+ -+ pll->n = div * mf_low / p1; -+ pll->m *= mf_low; -+ pll->p1 = p1; -+ dev_dbg(dev, "PLL: N %u M %u P1 %u\n", pll->n, pll->m, pll->p1); -+ return 0; -+ } -+ -+ dev_err(dev, "pll: no valid N and P1 divisors found.\n"); -+ return -EINVAL; -+} -+EXPORT_SYMBOL_GPL(aptina_pll_calculate); -+ -+MODULE_DESCRIPTION("Aptina PLL Helpers"); -+MODULE_AUTHOR("Laurent Pinchart "); -+MODULE_LICENSE("GPL v2"); -Index: linux-3.3.x86_64/drivers/media/video/aptina-pll.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/aptina-pll.h -@@ -0,0 +1,56 @@ -+/* -+ * Aptina Sensor PLL Configuration -+ * -+ * Copyright (C) 2012 Laurent Pinchart -+ * -+ * 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. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ */ -+ -+#ifndef __APTINA_PLL_H -+#define __APTINA_PLL_H -+ -+struct aptina_pll { -+ unsigned int ext_clock; -+ unsigned int pix_clock; -+ -+ unsigned int n; -+ unsigned int m; -+ unsigned int p1; -+}; -+ -+struct aptina_pll_limits { -+ unsigned int ext_clock_min; -+ unsigned int ext_clock_max; -+ unsigned int int_clock_min; -+ unsigned int int_clock_max; -+ unsigned int out_clock_min; -+ unsigned int out_clock_max; -+ unsigned int pix_clock_max; -+ -+ unsigned int n_min; -+ unsigned int n_max; -+ unsigned int m_min; -+ unsigned int m_max; -+ unsigned int p1_min; -+ unsigned int p1_max; -+}; -+ -+struct device; -+ -+int aptina_pll_calculate(struct device *dev, -+ const struct aptina_pll_limits *limits, -+ struct aptina_pll *pll); -+ -+#endif /* __APTINA_PLL_H */ -Index: linux-3.3.x86_64/drivers/media/video/mt9m032.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/video/mt9m032.c -@@ -0,0 +1,868 @@ -+/* -+ * Driver for MT9M032 CMOS Image Sensor from Micron -+ * -+ * Copyright (C) 2010-2011 Lund Engineering -+ * Contact: Gil Lund -+ * Author: Martin Hostettler -+ * -+ * 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. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "aptina-pll.h" -+ -+/* -+ * width and height include active boundary and black parts -+ * -+ * column 0- 15 active boundary -+ * column 16-1455 image -+ * column 1456-1471 active boundary -+ * column 1472-1599 black -+ * -+ * row 0- 51 black -+ * row 53- 59 active boundary -+ * row 60-1139 image -+ * row 1140-1147 active boundary -+ * row 1148-1151 black -+ */ -+ -+#define MT9M032_PIXEL_ARRAY_WIDTH 1600 -+#define MT9M032_PIXEL_ARRAY_HEIGHT 1152 -+ -+#define MT9M032_CHIP_VERSION 0x00 -+#define MT9M032_CHIP_VERSION_VALUE 0x1402 -+#define MT9M032_ROW_START 0x01 -+#define MT9M032_ROW_START_MIN 0 -+#define MT9M032_ROW_START_MAX 1152 -+#define MT9M032_ROW_START_DEF 60 -+#define MT9M032_COLUMN_START 0x02 -+#define MT9M032_COLUMN_START_MIN 0 -+#define MT9M032_COLUMN_START_MAX 1600 -+#define MT9M032_COLUMN_START_DEF 16 -+#define MT9M032_ROW_SIZE 0x03 -+#define MT9M032_ROW_SIZE_MIN 32 -+#define MT9M032_ROW_SIZE_MAX 1152 -+#define MT9M032_ROW_SIZE_DEF 1080 -+#define MT9M032_COLUMN_SIZE 0x04 -+#define MT9M032_COLUMN_SIZE_MIN 32 -+#define MT9M032_COLUMN_SIZE_MAX 1600 -+#define MT9M032_COLUMN_SIZE_DEF 1440 -+#define MT9M032_HBLANK 0x05 -+#define MT9M032_VBLANK 0x06 -+#define MT9M032_VBLANK_MAX 0x7ff -+#define MT9M032_SHUTTER_WIDTH_HIGH 0x08 -+#define MT9M032_SHUTTER_WIDTH_LOW 0x09 -+#define MT9M032_SHUTTER_WIDTH_MIN 1 -+#define MT9M032_SHUTTER_WIDTH_MAX 1048575 -+#define MT9M032_SHUTTER_WIDTH_DEF 1943 -+#define MT9M032_PIX_CLK_CTRL 0x0a -+#define MT9M032_PIX_CLK_CTRL_INV_PIXCLK 0x8000 -+#define MT9M032_RESTART 0x0b -+#define MT9M032_RESET 0x0d -+#define MT9M032_PLL_CONFIG1 0x11 -+#define MT9M032_PLL_CONFIG1_OUTDIV_MASK 0x3f -+#define MT9M032_PLL_CONFIG1_MUL_SHIFT 8 -+#define MT9M032_READ_MODE1 0x1e -+#define MT9M032_READ_MODE2 0x20 -+#define MT9M032_READ_MODE2_VFLIP_SHIFT 15 -+#define MT9M032_READ_MODE2_HFLIP_SHIFT 14 -+#define MT9M032_READ_MODE2_ROW_BLC 0x40 -+#define MT9M032_GAIN_GREEN1 0x2b -+#define MT9M032_GAIN_BLUE 0x2c -+#define MT9M032_GAIN_RED 0x2d -+#define MT9M032_GAIN_GREEN2 0x2e -+ -+/* write only */ -+#define MT9M032_GAIN_ALL 0x35 -+#define MT9M032_GAIN_DIGITAL_MASK 0x7f -+#define MT9M032_GAIN_DIGITAL_SHIFT 8 -+#define MT9M032_GAIN_AMUL_SHIFT 6 -+#define MT9M032_GAIN_ANALOG_MASK 0x3f -+#define MT9M032_FORMATTER1 0x9e -+#define MT9M032_FORMATTER2 0x9f -+#define MT9M032_FORMATTER2_DOUT_EN 0x1000 -+#define MT9M032_FORMATTER2_PIXCLK_EN 0x2000 -+ -+/* -+ * The available MT9M032 datasheet is missing documentation for register 0x10 -+ * MT9P031 seems to be close enough, so use constants from that datasheet for -+ * now. -+ * But keep the name MT9P031 to remind us, that this isn't really confirmed -+ * for this sensor. -+ */ -+#define MT9P031_PLL_CONTROL 0x10 -+#define MT9P031_PLL_CONTROL_PWROFF 0x0050 -+#define MT9P031_PLL_CONTROL_PWRON 0x0051 -+#define MT9P031_PLL_CONTROL_USEPLL 0x0052 -+#define MT9P031_PLL_CONFIG2 0x11 -+#define MT9P031_PLL_CONFIG2_P1_DIV_MASK 0x1f -+ -+struct mt9m032 { -+ struct v4l2_subdev subdev; -+ struct media_pad pad; -+ struct mt9m032_platform_data *pdata; -+ -+ unsigned int pix_clock; -+ -+ struct v4l2_ctrl_handler ctrls; -+ struct { -+ struct v4l2_ctrl *hflip; -+ struct v4l2_ctrl *vflip; -+ }; -+ -+ struct mutex lock; /* Protects streaming, format, interval and crop */ -+ -+ bool streaming; -+ -+ struct v4l2_mbus_framefmt format; -+ struct v4l2_rect crop; -+ struct v4l2_fract frame_interval; -+}; -+ -+#define to_mt9m032(sd) container_of(sd, struct mt9m032, subdev) -+#define to_dev(sensor) \ -+ (&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev) -+ -+static int mt9m032_read(struct i2c_client *client, u8 reg) -+{ -+ return i2c_smbus_read_word_swapped(client, reg); -+} -+ -+static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data) -+{ -+ return i2c_smbus_write_word_swapped(client, reg, data); -+} -+ -+static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width) -+{ -+ unsigned int effective_width; -+ u32 ns; -+ -+ effective_width = width + 716; /* empirical value */ -+ ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock); -+ dev_dbg(to_dev(sensor), "MT9M032 line time: %u ns\n", ns); -+ return ns; -+} -+ -+static int mt9m032_update_timing(struct mt9m032 *sensor, -+ struct v4l2_fract *interval) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ struct v4l2_rect *crop = &sensor->crop; -+ unsigned int min_vblank; -+ unsigned int vblank; -+ u32 row_time; -+ -+ if (!interval) -+ interval = &sensor->frame_interval; -+ -+ row_time = mt9m032_row_time(sensor, crop->width); -+ -+ vblank = div_u64(1000000000ULL * interval->numerator, -+ (u64)row_time * interval->denominator) -+ - crop->height; -+ -+ if (vblank > MT9M032_VBLANK_MAX) { -+ /* hardware limits to 11 bit values */ -+ interval->denominator = 1000; -+ interval->numerator = -+ div_u64((crop->height + MT9M032_VBLANK_MAX) * -+ (u64)row_time * interval->denominator, -+ 1000000000ULL); -+ vblank = div_u64(1000000000ULL * interval->numerator, -+ (u64)row_time * interval->denominator) -+ - crop->height; -+ } -+ /* enforce minimal 1.6ms blanking time. */ -+ min_vblank = 1600000 / row_time; -+ vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX); -+ -+ return mt9m032_write(client, MT9M032_VBLANK, vblank); -+} -+ -+static int mt9m032_update_geom_timing(struct mt9m032 *sensor) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ int ret; -+ -+ ret = mt9m032_write(client, MT9M032_COLUMN_SIZE, -+ sensor->crop.width - 1); -+ if (!ret) -+ ret = mt9m032_write(client, MT9M032_ROW_SIZE, -+ sensor->crop.height - 1); -+ if (!ret) -+ ret = mt9m032_write(client, MT9M032_COLUMN_START, -+ sensor->crop.left); -+ if (!ret) -+ ret = mt9m032_write(client, MT9M032_ROW_START, -+ sensor->crop.top); -+ if (!ret) -+ ret = mt9m032_update_timing(sensor, NULL); -+ return ret; -+} -+ -+static int update_formatter2(struct mt9m032 *sensor, bool streaming) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ u16 reg_val = MT9M032_FORMATTER2_DOUT_EN -+ | 0x0070; /* parts reserved! */ -+ /* possibly for changing to 14-bit mode */ -+ -+ if (streaming) -+ reg_val |= MT9M032_FORMATTER2_PIXCLK_EN; /* pixclock enable */ -+ -+ return mt9m032_write(client, MT9M032_FORMATTER2, reg_val); -+} -+ -+static int mt9m032_setup_pll(struct mt9m032 *sensor) -+{ -+ static const struct aptina_pll_limits limits = { -+ .ext_clock_min = 8000000, -+ .ext_clock_max = 16500000, -+ .int_clock_min = 2000000, -+ .int_clock_max = 24000000, -+ .out_clock_min = 322000000, -+ .out_clock_max = 693000000, -+ .pix_clock_max = 99000000, -+ .n_min = 1, -+ .n_max = 64, -+ .m_min = 16, -+ .m_max = 255, -+ .p1_min = 1, -+ .p1_max = 128, -+ }; -+ -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ struct mt9m032_platform_data *pdata = sensor->pdata; -+ struct aptina_pll pll; -+ int ret; -+ -+ pll.ext_clock = pdata->ext_clock; -+ pll.pix_clock = pdata->pix_clock; -+ -+ ret = aptina_pll_calculate(&client->dev, &limits, &pll); -+ if (ret < 0) -+ return ret; -+ -+ sensor->pix_clock = pdata->pix_clock; -+ -+ ret = mt9m032_write(client, MT9M032_PLL_CONFIG1, -+ (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) -+ | (pll.p1 - 1)); -+ if (!ret) -+ ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1); -+ if (!ret) -+ ret = mt9m032_write(client, MT9P031_PLL_CONTROL, -+ MT9P031_PLL_CONTROL_PWRON | -+ MT9P031_PLL_CONTROL_USEPLL); -+ if (!ret) /* more reserved, Continuous, Master Mode */ -+ ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006); -+ if (!ret) /* Set 14-bit mode, select 7 divider */ -+ ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e); -+ -+ return ret; -+} -+ -+/* ----------------------------------------------------------------------------- -+ * Subdev pad operations -+ */ -+ -+static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_fh *fh, -+ struct v4l2_subdev_mbus_code_enum *code) -+{ -+ if (code->index != 0) -+ return -EINVAL; -+ -+ code->code = V4L2_MBUS_FMT_Y8_1X8; -+ return 0; -+} -+ -+static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_fh *fh, -+ struct v4l2_subdev_frame_size_enum *fse) -+{ -+ if (fse->index != 0 || fse->code != V4L2_MBUS_FMT_Y8_1X8) -+ return -EINVAL; -+ -+ fse->min_width = MT9M032_COLUMN_SIZE_DEF; -+ fse->max_width = MT9M032_COLUMN_SIZE_DEF; -+ fse->min_height = MT9M032_ROW_SIZE_DEF; -+ fse->max_height = MT9M032_ROW_SIZE_DEF; -+ -+ return 0; -+} -+ -+/** -+ * __mt9m032_get_pad_crop() - get crop rect -+ * @sensor: pointer to the sensor struct -+ * @fh: file handle for getting the try crop rect from -+ * @which: select try or active crop rect -+ * -+ * Returns a pointer the current active or fh relative try crop rect -+ */ -+static struct v4l2_rect * -+__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, -+ enum v4l2_subdev_format_whence which) -+{ -+ switch (which) { -+ case V4L2_SUBDEV_FORMAT_TRY: -+ return v4l2_subdev_get_try_crop(fh, 0); -+ case V4L2_SUBDEV_FORMAT_ACTIVE: -+ return &sensor->crop; -+ default: -+ return NULL; -+ } -+} -+ -+/** -+ * __mt9m032_get_pad_format() - get format -+ * @sensor: pointer to the sensor struct -+ * @fh: file handle for getting the try format from -+ * @which: select try or active format -+ * -+ * Returns a pointer the current active or fh relative try format -+ */ -+static struct v4l2_mbus_framefmt * -+__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, -+ enum v4l2_subdev_format_whence which) -+{ -+ switch (which) { -+ case V4L2_SUBDEV_FORMAT_TRY: -+ return v4l2_subdev_get_try_format(fh, 0); -+ case V4L2_SUBDEV_FORMAT_ACTIVE: -+ return &sensor->format; -+ default: -+ return NULL; -+ } -+} -+ -+static int mt9m032_get_pad_format(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_fh *fh, -+ struct v4l2_subdev_format *fmt) -+{ -+ struct mt9m032 *sensor = to_mt9m032(subdev); -+ -+ mutex_lock(&sensor->lock); -+ fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which); -+ mutex_unlock(&sensor->lock); -+ -+ return 0; -+} -+ -+static int mt9m032_set_pad_format(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_fh *fh, -+ struct v4l2_subdev_format *fmt) -+{ -+ struct mt9m032 *sensor = to_mt9m032(subdev); -+ int ret; -+ -+ mutex_lock(&sensor->lock); -+ -+ if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { -+ ret = -EBUSY; -+ goto done; -+ } -+ -+ /* Scaling is not supported, the format is thus fixed. */ -+ ret = mt9m032_get_pad_format(subdev, fh, fmt); -+ -+done: -+ mutex_lock(&sensor->lock); -+ return ret; -+} -+ -+static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_fh *fh, -+ struct v4l2_subdev_crop *crop) -+{ -+ struct mt9m032 *sensor = to_mt9m032(subdev); -+ -+ mutex_lock(&sensor->lock); -+ crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which); -+ mutex_unlock(&sensor->lock); -+ -+ return 0; -+} -+ -+static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_fh *fh, -+ struct v4l2_subdev_crop *crop) -+{ -+ struct mt9m032 *sensor = to_mt9m032(subdev); -+ struct v4l2_mbus_framefmt *format; -+ struct v4l2_rect *__crop; -+ struct v4l2_rect rect; -+ int ret = 0; -+ -+ mutex_lock(&sensor->lock); -+ -+ if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { -+ ret = -EBUSY; -+ goto done; -+ } -+ -+ /* Clamp the crop rectangle boundaries and align them to a multiple of 2 -+ * pixels to ensure a GRBG Bayer pattern. -+ */ -+ rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN, -+ MT9M032_COLUMN_START_MAX); -+ rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN, -+ MT9M032_ROW_START_MAX); -+ rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN, -+ MT9M032_COLUMN_SIZE_MAX); -+ rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN, -+ MT9M032_ROW_SIZE_MAX); -+ -+ rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left); -+ rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); -+ -+ __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which); -+ -+ if (rect.width != __crop->width || rect.height != __crop->height) { -+ /* Reset the output image size if the crop rectangle size has -+ * been modified. -+ */ -+ format = __mt9m032_get_pad_format(sensor, fh, crop->which); -+ format->width = rect.width; -+ format->height = rect.height; -+ } -+ -+ *__crop = rect; -+ crop->rect = rect; -+ -+ if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) -+ ret = mt9m032_update_geom_timing(sensor); -+ -+done: -+ mutex_unlock(&sensor->lock); -+ return ret; -+} -+ -+static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_frame_interval *fi) -+{ -+ struct mt9m032 *sensor = to_mt9m032(subdev); -+ -+ mutex_lock(&sensor->lock); -+ memset(fi, 0, sizeof(*fi)); -+ fi->interval = sensor->frame_interval; -+ mutex_unlock(&sensor->lock); -+ -+ return 0; -+} -+ -+static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_frame_interval *fi) -+{ -+ struct mt9m032 *sensor = to_mt9m032(subdev); -+ int ret; -+ -+ mutex_lock(&sensor->lock); -+ -+ if (sensor->streaming) { -+ ret = -EBUSY; -+ goto done; -+ } -+ -+ /* Avoid divisions by 0. */ -+ if (fi->interval.denominator == 0) -+ fi->interval.denominator = 1; -+ -+ ret = mt9m032_update_timing(sensor, &fi->interval); -+ if (!ret) -+ sensor->frame_interval = fi->interval; -+ -+done: -+ mutex_unlock(&sensor->lock); -+ return ret; -+} -+ -+static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming) -+{ -+ struct mt9m032 *sensor = to_mt9m032(subdev); -+ int ret; -+ -+ mutex_lock(&sensor->lock); -+ ret = update_formatter2(sensor, streaming); -+ if (!ret) -+ sensor->streaming = streaming; -+ mutex_unlock(&sensor->lock); -+ -+ return ret; -+} -+ -+/* ----------------------------------------------------------------------------- -+ * V4L2 subdev core operations -+ */ -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int mt9m032_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct mt9m032 *sensor = to_mt9m032(sd); -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ int val; -+ -+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) -+ return -EINVAL; -+ if (reg->match.addr != client->addr) -+ return -ENODEV; -+ -+ val = mt9m032_read(client, reg->reg); -+ if (val < 0) -+ return -EIO; -+ -+ reg->size = 2; -+ reg->val = val; -+ -+ return 0; -+} -+ -+static int mt9m032_s_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct mt9m032 *sensor = to_mt9m032(sd); -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ -+ if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) -+ return -EINVAL; -+ -+ if (reg->match.addr != client->addr) -+ return -ENODEV; -+ -+ return mt9m032_write(client, reg->reg, reg->val); -+} -+#endif -+ -+/* ----------------------------------------------------------------------------- -+ * V4L2 subdev control operations -+ */ -+ -+static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT) -+ | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT) -+ | MT9M032_READ_MODE2_ROW_BLC -+ | 0x0007; -+ -+ return mt9m032_write(client, MT9M032_READ_MODE2, reg_val); -+} -+ -+static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ int digital_gain_val; /* in 1/8th (0..127) */ -+ int analog_mul; /* 0 or 1 */ -+ int analog_gain_val; /* in 1/16th. (0..63) */ -+ u16 reg_val; -+ -+ digital_gain_val = 51; /* from setup example */ -+ -+ if (val < 63) { -+ analog_mul = 0; -+ analog_gain_val = val; -+ } else { -+ analog_mul = 1; -+ analog_gain_val = val / 2; -+ } -+ -+ /* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */ -+ /* overall_gain = a_gain * (1 + digital_gain_val / 8) */ -+ -+ reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK) -+ << MT9M032_GAIN_DIGITAL_SHIFT) -+ | ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT) -+ | (analog_gain_val & MT9M032_GAIN_ANALOG_MASK); -+ -+ return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val); -+} -+ -+static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) { -+ /* round because of multiplier used for values >= 63 */ -+ ctrl->val &= ~1; -+ } -+ -+ return 0; -+} -+ -+static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct mt9m032 *sensor = -+ container_of(ctrl->handler, struct mt9m032, ctrls); -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); -+ int ret; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_GAIN: -+ return mt9m032_set_gain(sensor, ctrl->val); -+ -+ case V4L2_CID_HFLIP: -+ /* case V4L2_CID_VFLIP: -- In the same cluster */ -+ return update_read_mode2(sensor, sensor->vflip->val, -+ sensor->hflip->val); -+ -+ case V4L2_CID_EXPOSURE: -+ ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH, -+ (ctrl->val >> 16) & 0xffff); -+ if (ret < 0) -+ return ret; -+ -+ return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW, -+ ctrl->val & 0xffff); -+ } -+ -+ return 0; -+} -+ -+static struct v4l2_ctrl_ops mt9m032_ctrl_ops = { -+ .s_ctrl = mt9m032_set_ctrl, -+ .try_ctrl = mt9m032_try_ctrl, -+}; -+ -+/* -------------------------------------------------------------------------- */ -+ -+static const struct v4l2_subdev_core_ops mt9m032_core_ops = { -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = mt9m032_g_register, -+ .s_register = mt9m032_s_register, -+#endif -+}; -+ -+static const struct v4l2_subdev_video_ops mt9m032_video_ops = { -+ .s_stream = mt9m032_s_stream, -+ .g_frame_interval = mt9m032_get_frame_interval, -+ .s_frame_interval = mt9m032_set_frame_interval, -+}; -+ -+static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = { -+ .enum_mbus_code = mt9m032_enum_mbus_code, -+ .enum_frame_size = mt9m032_enum_frame_size, -+ .get_fmt = mt9m032_get_pad_format, -+ .set_fmt = mt9m032_set_pad_format, -+ .set_crop = mt9m032_set_pad_crop, -+ .get_crop = mt9m032_get_pad_crop, -+}; -+ -+static const struct v4l2_subdev_ops mt9m032_ops = { -+ .core = &mt9m032_core_ops, -+ .video = &mt9m032_video_ops, -+ .pad = &mt9m032_pad_ops, -+}; -+ -+/* ----------------------------------------------------------------------------- -+ * Driver initialization and probing -+ */ -+ -+static int mt9m032_probe(struct i2c_client *client, -+ const struct i2c_device_id *devid) -+{ -+ struct i2c_adapter *adapter = client->adapter; -+ struct mt9m032 *sensor; -+ int chip_version; -+ int ret; -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { -+ dev_warn(&client->dev, -+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); -+ return -EIO; -+ } -+ -+ if (!client->dev.platform_data) -+ return -ENODEV; -+ -+ sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); -+ if (sensor == NULL) -+ return -ENOMEM; -+ -+ mutex_init(&sensor->lock); -+ -+ sensor->pdata = client->dev.platform_data; -+ -+ v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops); -+ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -+ -+ chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION); -+ if (chip_version != MT9M032_CHIP_VERSION_VALUE) { -+ dev_err(&client->dev, "MT9M032 not detected, wrong version " -+ "0x%04x\n", chip_version); -+ ret = -ENODEV; -+ goto error_sensor; -+ } -+ -+ dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n", -+ client->addr); -+ -+ sensor->frame_interval.numerator = 1; -+ sensor->frame_interval.denominator = 30; -+ -+ sensor->crop.left = MT9M032_COLUMN_START_DEF; -+ sensor->crop.top = MT9M032_ROW_START_DEF; -+ sensor->crop.width = MT9M032_COLUMN_SIZE_DEF; -+ sensor->crop.height = MT9M032_ROW_SIZE_DEF; -+ -+ sensor->format.width = sensor->crop.width; -+ sensor->format.height = sensor->crop.height; -+ sensor->format.code = V4L2_MBUS_FMT_Y8_1X8; -+ sensor->format.field = V4L2_FIELD_NONE; -+ sensor->format.colorspace = V4L2_COLORSPACE_SRGB; -+ -+ v4l2_ctrl_handler_init(&sensor->ctrls, 4); -+ -+ v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, -+ V4L2_CID_GAIN, 0, 127, 1, 64); -+ -+ sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, -+ &mt9m032_ctrl_ops, -+ V4L2_CID_HFLIP, 0, 1, 1, 0); -+ sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, -+ &mt9m032_ctrl_ops, -+ V4L2_CID_VFLIP, 0, 1, 1, 0); -+ -+ v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, -+ V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN, -+ MT9M032_SHUTTER_WIDTH_MAX, 1, -+ MT9M032_SHUTTER_WIDTH_DEF); -+ -+ if (sensor->ctrls.error) { -+ ret = sensor->ctrls.error; -+ dev_err(&client->dev, "control initialization error %d\n", ret); -+ goto error_ctrl; -+ } -+ -+ v4l2_ctrl_cluster(2, &sensor->hflip); -+ -+ sensor->subdev.ctrl_handler = &sensor->ctrls; -+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE; -+ ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0); -+ if (ret < 0) -+ goto error_ctrl; -+ -+ ret = mt9m032_write(client, MT9M032_RESET, 1); /* reset on */ -+ if (ret < 0) -+ goto error_entity; -+ mt9m032_write(client, MT9M032_RESET, 0); /* reset off */ -+ if (ret < 0) -+ goto error_entity; -+ -+ ret = mt9m032_setup_pll(sensor); -+ if (ret < 0) -+ goto error_entity; -+ usleep_range(10000, 11000); -+ -+ ret = v4l2_ctrl_handler_setup(&sensor->ctrls); -+ if (ret < 0) -+ goto error_entity; -+ -+ /* SIZE */ -+ ret = mt9m032_update_geom_timing(sensor); -+ if (ret < 0) -+ goto error_entity; -+ -+ ret = mt9m032_write(client, 0x41, 0x0000); /* reserved !!! */ -+ if (ret < 0) -+ goto error_entity; -+ ret = mt9m032_write(client, 0x42, 0x0003); /* reserved !!! */ -+ if (ret < 0) -+ goto error_entity; -+ ret = mt9m032_write(client, 0x43, 0x0003); /* reserved !!! */ -+ if (ret < 0) -+ goto error_entity; -+ ret = mt9m032_write(client, 0x7f, 0x0000); /* reserved !!! */ -+ if (ret < 0) -+ goto error_entity; -+ if (sensor->pdata->invert_pixclock) { -+ ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL, -+ MT9M032_PIX_CLK_CTRL_INV_PIXCLK); -+ if (ret < 0) -+ goto error_entity; -+ } -+ -+ ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */ -+ if (ret < 0) -+ goto error_entity; -+ msleep(100); -+ ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */ -+ if (ret < 0) -+ goto error_entity; -+ msleep(100); -+ ret = update_formatter2(sensor, false); -+ if (ret < 0) -+ goto error_entity; -+ -+ return ret; -+ -+error_entity: -+ media_entity_cleanup(&sensor->subdev.entity); -+error_ctrl: -+ v4l2_ctrl_handler_free(&sensor->ctrls); -+error_sensor: -+ mutex_destroy(&sensor->lock); -+ kfree(sensor); -+ return ret; -+} -+ -+static int mt9m032_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *subdev = i2c_get_clientdata(client); -+ struct mt9m032 *sensor = to_mt9m032(subdev); -+ -+ v4l2_device_unregister_subdev(&sensor->subdev); -+ v4l2_ctrl_handler_free(&sensor->ctrls); -+ media_entity_cleanup(&sensor->subdev.entity); -+ mutex_destroy(&sensor->lock); -+ kfree(sensor); -+ return 0; -+} -+ -+static const struct i2c_device_id mt9m032_id_table[] = { -+ { MT9M032_NAME, 0 }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(i2c, mt9m032_id_table); -+ -+static struct i2c_driver mt9m032_i2c_driver = { -+ .driver = { -+ .name = MT9M032_NAME, -+ }, -+ .probe = mt9m032_probe, -+ .remove = mt9m032_remove, -+ .id_table = mt9m032_id_table, -+}; -+ -+module_i2c_driver(mt9m032_i2c_driver); -+ -+MODULE_AUTHOR("Martin Hostettler "); -+MODULE_DESCRIPTION("MT9M032 camera sensor driver"); -+MODULE_LICENSE("GPL v2"); -Index: linux-3.3.x86_64/include/media/mt9m032.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/include/media/mt9m032.h -@@ -0,0 +1,36 @@ -+/* -+ * Driver for MT9M032 CMOS Image Sensor from Micron -+ * -+ * Copyright (C) 2010-2011 Lund Engineering -+ * Contact: Gil Lund -+ * Author: Martin Hostettler -+ * -+ * 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. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ */ -+ -+#ifndef MT9M032_H -+#define MT9M032_H -+ -+#define MT9M032_NAME "mt9m032" -+#define MT9M032_I2C_ADDR (0xb8 >> 1) -+ -+struct mt9m032_platform_data { -+ u32 ext_clock; -+ u32 pix_clock; -+ bool invert_pixclock; -+ -+}; -+#endif /* MT9M032_H */ -Index: linux-3.3.x86_64/drivers/media/video/v4l2-dev.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/v4l2-dev.c -+++ linux-3.3.x86_64/drivers/media/video/v4l2-dev.c -@@ -788,7 +788,7 @@ static void __exit videodev_exit(void) - unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); - } - --module_init(videodev_init) -+subsys_initcall(videodev_init); - module_exit(videodev_exit) - - MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab "); -Index: linux-3.3.x86_64/drivers/media/media-devnode.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/media-devnode.c -+++ linux-3.3.x86_64/drivers/media/media-devnode.c -@@ -312,7 +312,7 @@ static void __exit media_devnode_exit(vo - unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); - } - --module_init(media_devnode_init) -+subsys_initcall(media_devnode_init); - module_exit(media_devnode_exit) - - MODULE_AUTHOR("Laurent Pinchart "); -Index: linux-3.3.x86_64/drivers/media/rc/mceusb.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/mceusb.c -+++ linux-3.3.x86_64/drivers/media/rc/mceusb.c -@@ -361,6 +361,8 @@ static struct usb_device_id mceusb_dev_t - { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, - /* Formosa Industrial Computing */ - { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, -+ /* Formosa Industrial Computing */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe042) }, - /* Fintek eHome Infrared Transceiver (HP branded) */ - { USB_DEVICE(VENDOR_FINTEK, 0x5168) }, - /* Fintek eHome Infrared Transceiver */ -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/au8522_dig.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/frontends/au8522_dig.c -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/au8522_dig.c -@@ -604,6 +604,11 @@ static int au8522_set_frontend(struct dv - - au8522_enable_modulation(fe, c->modulation); - -+ /* Allow the tuner to settle */ -+ msleep(100); -+ -+ au8522_enable_modulation(fe, c->modulation); -+ - state->current_frequency = c->frequency; - - return 0; -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/dib0700_core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/dib0700_core.c -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/dib0700_core.c -@@ -677,11 +677,9 @@ static void dib0700_rc_urb_completion(st - u8 toggle; - - deb_info("%s()\n", __func__); -- if (d == NULL) -- return; -- - if (d->rc_dev == NULL) { - /* This will occur if disable_rc_polling=1 */ -+ kfree(purb->transfer_buffer); - usb_free_urb(purb); - return; - } -@@ -690,6 +688,7 @@ static void dib0700_rc_urb_completion(st - - if (purb->status < 0) { - deb_info("discontinuing polling\n"); -+ kfree(purb->transfer_buffer); - usb_free_urb(purb); - return; - } -@@ -784,8 +783,11 @@ int dib0700_rc_setup(struct dvb_usb_devi - dib0700_rc_urb_completion, d); - - ret = usb_submit_urb(purb, GFP_ATOMIC); -- if (ret) -+ if (ret) { - err("rc submit urb failed\n"); -+ kfree(purb->transfer_buffer); -+ usb_free_urb(purb); -+ } - - return ret; - } -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9015.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/af9015.c -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9015.c -@@ -1164,6 +1164,41 @@ static int af9015_af9013_sleep(struct dv - return ret; - } - -+/* override tuner callbacks for resource locking */ -+static int af9015_tuner_init(struct dvb_frontend *fe) -+{ -+ int ret; -+ struct dvb_usb_adapter *adap = fe->dvb->priv; -+ struct af9015_state *priv = adap->dev->priv; -+ -+ if (mutex_lock_interruptible(&adap->dev->usb_mutex)) -+ return -EAGAIN; -+ -+ ret = priv->tuner_init[adap->id](fe); -+ -+ mutex_unlock(&adap->dev->usb_mutex); -+ -+ return ret; -+} -+ -+/* override tuner callbacks for resource locking */ -+static int af9015_tuner_sleep(struct dvb_frontend *fe) -+{ -+ int ret; -+ struct dvb_usb_adapter *adap = fe->dvb->priv; -+ struct af9015_state *priv = adap->dev->priv; -+ -+ if (mutex_lock_interruptible(&adap->dev->usb_mutex)) -+ return -EAGAIN; -+ -+ ret = priv->tuner_sleep[adap->id](fe); -+ -+ mutex_unlock(&adap->dev->usb_mutex); -+ -+ return ret; -+} -+ -+ - static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) - { - int ret; -@@ -1283,6 +1318,7 @@ static struct mxl5007t_config af9015_mxl - static int af9015_tuner_attach(struct dvb_usb_adapter *adap) - { - int ret; -+ struct af9015_state *state = adap->dev->priv; - deb_info("%s:\n", __func__); - - switch (af9015_af9013_config[adap->id].tuner) { -@@ -1340,6 +1376,19 @@ static int af9015_tuner_attach(struct dv - err("Unknown tuner id:%d", - af9015_af9013_config[adap->id].tuner); - } -+ -+ if (adap->fe_adap[0].fe->ops.tuner_ops.init) { -+ state->tuner_init[adap->id] = -+ adap->fe_adap[0].fe->ops.tuner_ops.init; -+ adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init; -+ } -+ -+ if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) { -+ state->tuner_sleep[adap->id] = -+ adap->fe_adap[0].fe->ops.tuner_ops.sleep; -+ adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep; -+ } -+ - return ret; - } - -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9015.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/af9015.h -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9015.h -@@ -108,6 +108,8 @@ struct af9015_state { - int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); - int (*init[2]) (struct dvb_frontend *fe); - int (*sleep[2]) (struct dvb_frontend *fe); -+ int (*tuner_init[2]) (struct dvb_frontend *fe); -+ int (*tuner_sleep[2]) (struct dvb_frontend *fe); - }; - - struct af9015_config { -Index: linux-3.3.x86_64/drivers/media/rc/rc-main.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/rc/rc-main.c -+++ linux-3.3.x86_64/drivers/media/rc/rc-main.c -@@ -1029,6 +1029,7 @@ EXPORT_SYMBOL_GPL(rc_free_device); - - int rc_register_device(struct rc_dev *dev) - { -+ static bool raw_init = false; /* raw decoders loaded? */ - static atomic_t devno = ATOMIC_INIT(0); - struct rc_map *rc_map; - const char *path; -@@ -1103,6 +1104,12 @@ int rc_register_device(struct rc_dev *de - kfree(path); - - if (dev->driver_type == RC_DRIVER_IR_RAW) { -+ /* Load raw decoders, if they aren't already */ -+ if (!raw_init) { -+ IR_dprintk(1, "Loading raw decoders\n"); -+ ir_raw_init(); -+ raw_init = true; -+ } - rc = ir_raw_event_register(dev); - if (rc < 0) - goto out_input; -@@ -1176,8 +1183,6 @@ static int __init rc_core_init(void) - return rc; - } - -- /* Initialize/load the decoders/keymap code that will be used */ -- ir_raw_init(); - rc_map_register(&empty_map); - - return 0; -Index: linux-3.3.x86_64/drivers/media/video/soc_camera.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/soc_camera.c -+++ linux-3.3.x86_64/drivers/media/video/soc_camera.c -@@ -526,10 +526,6 @@ static int soc_camera_open(struct file * - }, - }; - -- ret = soc_camera_power_on(icd, icl); -- if (ret < 0) -- goto epower; -- - /* The camera could have been already on, try to reset */ - if (icl->reset) - icl->reset(icd->pdev); -@@ -540,6 +536,10 @@ static int soc_camera_open(struct file * - goto eiciadd; - } - -+ ret = soc_camera_power_on(icd, icl); -+ if (ret < 0) -+ goto epower; -+ - pm_runtime_enable(&icd->vdev->dev); - ret = pm_runtime_resume(&icd->vdev->dev); - if (ret < 0 && ret != -ENOSYS) -@@ -578,10 +578,10 @@ einitvb: - esfmt: - pm_runtime_disable(&icd->vdev->dev); - eresume: -- ici->ops->remove(icd); --eiciadd: - soc_camera_power_off(icd, icl); - epower: -+ ici->ops->remove(icd); -+eiciadd: - icd->use_count--; - module_put(ici->ops->owner); - -@@ -1050,6 +1050,14 @@ static int soc_camera_probe(struct soc_c - if (ret < 0) - goto ereg; - -+ /* The camera could have been already on, try to reset */ -+ if (icl->reset) -+ icl->reset(icd->pdev); -+ -+ ret = ici->ops->add(icd); -+ if (ret < 0) -+ goto eadd; -+ - /* - * This will not yet call v4l2_subdev_core_ops::s_power(1), because the - * subdevice has not been initialised yet. We'll have to call it once -@@ -1060,14 +1068,6 @@ static int soc_camera_probe(struct soc_c - if (ret < 0) - goto epower; - -- /* The camera could have been already on, try to reset */ -- if (icl->reset) -- icl->reset(icd->pdev); -- -- ret = ici->ops->add(icd); -- if (ret < 0) -- goto eadd; -- - /* Must have icd->vdev before registering the device */ - ret = video_dev_create(icd); - if (ret < 0) -@@ -1165,10 +1165,10 @@ eadddev: - video_device_release(icd->vdev); - icd->vdev = NULL; - evdc: -- ici->ops->remove(icd); --eadd: - soc_camera_power_off(icd, icl); - epower: -+ ici->ops->remove(icd); -+eadd: - regulator_bulk_free(icl->num_regulators, icl->regulators); - ereg: - v4l2_ctrl_handler_free(&icd->ctrl_handler); -Index: linux-3.3.x86_64/drivers/media/video/sh_mobile_ceu_camera.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/sh_mobile_ceu_camera.c -+++ linux-3.3.x86_64/drivers/media/video/sh_mobile_ceu_camera.c -@@ -112,6 +112,10 @@ struct sh_mobile_ceu_dev { - - u32 cflcr; - -+ /* static max sizes either from platform data or default */ -+ int max_width; -+ int max_height; -+ - enum v4l2_field field; - int sequence; - -@@ -1081,7 +1085,15 @@ static int sh_mobile_ceu_get_formats(str - if (ret < 0) - return ret; - -- while ((mf.width > 2560 || mf.height > 1920) && shift < 4) { -+ /* -+ * All currently existing CEU implementations support 2560x1920 -+ * or larger frames. If the sensor is proposing too big a frame, -+ * don't bother with possibly supportred by the CEU larger -+ * sizes, just try VGA multiples. If needed, this can be -+ * adjusted in the future. -+ */ -+ while ((mf.width > pcdev->max_width || -+ mf.height > pcdev->max_height) && shift < 4) { - /* Try 2560x1920, 1280x960, 640x480, 320x240 */ - mf.width = 2560 >> shift; - mf.height = 1920 >> shift; -@@ -1377,6 +1389,8 @@ static int client_s_crop(struct soc_came - static int client_s_fmt(struct soc_camera_device *icd, - struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) - { -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->parent; -@@ -1410,8 +1424,8 @@ static int client_s_fmt(struct soc_camer - if (ret < 0) - return ret; - -- max_width = min(cap.bounds.width, 2560); -- max_height = min(cap.bounds.height, 1920); -+ max_width = min(cap.bounds.width, pcdev->max_width); -+ max_height = min(cap.bounds.height, pcdev->max_height); - - /* Camera set a format, but geometry is not precise, try to improve */ - tmp_w = mf->width; -@@ -1551,7 +1565,7 @@ static int sh_mobile_ceu_set_crop(struct - if (ret < 0) - return ret; - -- if (mf.width > 2560 || mf.height > 1920) -+ if (mf.width > pcdev->max_width || mf.height > pcdev->max_height) - return -EINVAL; - - /* 4. Calculate camera scales */ -@@ -1834,6 +1848,8 @@ static int sh_mobile_ceu_set_fmt(struct - static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) - { -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct sh_mobile_ceu_dev *pcdev = ici->priv; - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -@@ -1854,8 +1870,8 @@ static int sh_mobile_ceu_try_fmt(struct - /* FIXME: calculate using depth and bus width */ - - /* CFSZR requires height and width to be 4-pixel aligned */ -- v4l_bound_align_image(&pix->width, 2, 2560, 2, -- &pix->height, 4, 1920, 2, 0); -+ v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2, -+ &pix->height, 4, pcdev->max_height, 2, 0); - - width = pix->width; - height = pix->height; -@@ -1890,8 +1906,8 @@ static int sh_mobile_ceu_try_fmt(struct - * requested a bigger rectangle, it will not return a - * smaller one. - */ -- mf.width = 2560; -- mf.height = 1920; -+ mf.width = pcdev->max_width; -+ mf.height = pcdev->max_height; - ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - try_mbus_fmt, &mf); -@@ -2082,6 +2098,9 @@ static int __devinit sh_mobile_ceu_probe - goto exit_kfree; - } - -+ pcdev->max_width = pcdev->pdata->max_width ? : 2560; -+ pcdev->max_height = pcdev->pdata->max_height ? : 1920; -+ - base = ioremap_nocache(res->start, resource_size(res)); - if (!base) { - err = -ENXIO; -Index: linux-3.3.x86_64/include/media/sh_mobile_ceu.h -=================================================================== ---- linux-3.3.x86_64.orig/include/media/sh_mobile_ceu.h -+++ linux-3.3.x86_64/include/media/sh_mobile_ceu.h -@@ -18,6 +18,8 @@ struct sh_mobile_ceu_companion { - - struct sh_mobile_ceu_info { - unsigned long flags; -+ int max_width; -+ int max_height; - struct sh_mobile_ceu_companion *csi2; - }; - -Index: linux-3.3.x86_64/drivers/media/video/pxa_camera.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/pxa_camera.c -+++ linux-3.3.x86_64/drivers/media/video/pxa_camera.c -@@ -921,12 +921,12 @@ static void pxa_camera_activate(struct p - /* "Safe default" - 13MHz */ - recalculate_fifo_timeout(pcdev, 13000000); - -- clk_enable(pcdev->clk); -+ clk_prepare_enable(pcdev->clk); - } - - static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) - { -- clk_disable(pcdev->clk); -+ clk_disable_unprepare(pcdev->clk); - } - - static irqreturn_t pxa_camera_irq(int irq, void *data) -Index: linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-i2c.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/em28xx/em28xx-i2c.c -+++ linux-3.3.x86_64/drivers/media/video/em28xx/em28xx-i2c.c -@@ -41,14 +41,6 @@ static unsigned int i2c_debug; - module_param(i2c_debug, int, 0644); - MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -- --#define dprintk1(lvl, fmt, args...) \ --do { \ -- if (i2c_debug >= lvl) { \ -- printk(fmt, ##args); \ -- } \ --} while (0) -- - #define dprintk2(lvl, fmt, args...) \ - do { \ - if (i2c_debug >= lvl) { \ -Index: linux-3.3.x86_64/drivers/media/video/marvell-ccic/mcam-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/marvell-ccic/mcam-core.c -+++ linux-3.3.x86_64/drivers/media/video/marvell-ccic/mcam-core.c -@@ -509,11 +509,17 @@ static void mcam_sg_next_buffer(struct m - - buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); - list_del_init(&buf->queue); -+ /* -+ * Very Bad Not Good Things happen if you don't clear -+ * C1_DESC_ENA before making any descriptor changes. -+ */ -+ mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); - mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa); - mcam_reg_write(cam, REG_DESC_LEN_Y, - buf->dma_desc_nent*sizeof(struct mcam_dma_desc)); - mcam_reg_write(cam, REG_DESC_LEN_U, 0); - mcam_reg_write(cam, REG_DESC_LEN_V, 0); -+ mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); - cam->vb_bufs[0] = buf; - } - -@@ -533,7 +539,6 @@ static void mcam_ctlr_dma_sg(struct mcam - - mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); - mcam_sg_next_buffer(cam); -- mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); - cam->nbufs = 3; - } - -@@ -556,17 +561,16 @@ static void mcam_dma_sg_done(struct mcam - struct mcam_vb_buffer *buf = cam->vb_bufs[0]; - - /* -- * Very Bad Not Good Things happen if you don't clear -- * C1_DESC_ENA before making any descriptor changes. -+ * If we're no longer supposed to be streaming, don't do anything. - */ -- mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); -+ if (cam->state != S_STREAMING) -+ return; - /* - * If we have another buffer available, put it in and - * restart the engine. - */ - if (!list_empty(&cam->buffers)) { - mcam_sg_next_buffer(cam); -- mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); - mcam_ctlr_start(cam); - /* - * Otherwise set CF_SG_RESTART and the controller will -@@ -737,7 +741,14 @@ static void mcam_ctlr_stop_dma(struct mc - mcam_ctlr_stop(cam); - cam->state = S_IDLE; - spin_unlock_irqrestore(&cam->dev_lock, flags); -- msleep(40); -+ /* -+ * This is a brutally long sleep, but experience shows that -+ * it can take the controller a while to get the message that -+ * it needs to stop grabbing frames. In particular, we can -+ * sometimes (on mmp) get a frame at the end WITHOUT the -+ * start-of-frame indication. -+ */ -+ msleep(150); - if (test_bit(CF_DMA_ACTIVE, &cam->flags)) - cam_err(cam, "Timeout waiting for DMA to end\n"); - /* This would be bad news - what now? */ -@@ -880,6 +891,7 @@ static int mcam_read_setup(struct mcam_c - * Turn it loose. - */ - spin_lock_irqsave(&cam->dev_lock, flags); -+ clear_bit(CF_DMA_ACTIVE, &cam->flags); - mcam_reset_buffers(cam); - mcam_ctlr_irq_enable(cam); - cam->state = S_STREAMING; -@@ -922,7 +934,7 @@ static void mcam_vb_buf_queue(struct vb2 - spin_lock_irqsave(&cam->dev_lock, flags); - start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers); - list_add(&mvb->queue, &cam->buffers); -- if (test_bit(CF_SG_RESTART, &cam->flags)) -+ if (cam->state == S_STREAMING && test_bit(CF_SG_RESTART, &cam->flags)) - mcam_sg_restart(cam); - spin_unlock_irqrestore(&cam->dev_lock, flags); - if (start) -@@ -1555,15 +1567,12 @@ static int mcam_v4l_release(struct file - { - struct mcam_camera *cam = filp->private_data; - -- cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames, -+ cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", frames, - singles, delivered); - mutex_lock(&cam->s_mutex); - (cam->users)--; -- if (filp == cam->owner) { -- mcam_ctlr_stop_dma(cam); -- cam->owner = NULL; -- } - if (cam->users == 0) { -+ mcam_ctlr_stop_dma(cam); - mcam_cleanup_vb2(cam); - mcam_ctlr_power_down(cam); - if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) -@@ -1688,6 +1697,8 @@ int mccic_irq(struct mcam_camera *cam, u - if (irqs & (IRQ_EOF0 << frame)) { - mcam_frame_complete(cam, frame); - handled = 1; -+ if (cam->buffer_mode == B_DMA_sg) -+ break; - } - /* - * If a frame starts, note that we have DMA active. This -Index: linux-3.3.x86_64/drivers/media/video/marvell-ccic/mcam-core.h -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/marvell-ccic/mcam-core.h -+++ linux-3.3.x86_64/drivers/media/video/marvell-ccic/mcam-core.h -@@ -107,7 +107,6 @@ struct mcam_camera { - enum mcam_state state; - unsigned long flags; /* Buffer status, mainly (dev_lock) */ - int users; /* How many open FDs */ -- struct file *owner; /* Who has data access (v4l2) */ - - /* - * Subsystem structures. -Index: linux-3.3.x86_64/drivers/media/video/marvell-ccic/mmp-driver.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/marvell-ccic/mmp-driver.c -+++ linux-3.3.x86_64/drivers/media/video/marvell-ccic/mmp-driver.c -@@ -106,6 +106,13 @@ static struct mmp_camera *mmpcam_find_de - /* - * Power control. - */ -+static void mmpcam_power_up_ctlr(struct mmp_camera *cam) -+{ -+ iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); -+ iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); -+ mdelay(1); -+} -+ - static void mmpcam_power_up(struct mcam_camera *mcam) - { - struct mmp_camera *cam = mcam_to_cam(mcam); -@@ -113,9 +120,7 @@ static void mmpcam_power_up(struct mcam_ - /* - * Turn on power and clocks to the controller. - */ -- iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); -- iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); -- mdelay(1); -+ mmpcam_power_up_ctlr(cam); - /* - * Provide power to the sensor. - */ -@@ -335,7 +340,7 @@ static int mmpcam_resume(struct platform - * touch a register even if nothing was active before; trust - * me, it's better this way. - */ -- mmpcam_power_up(&cam->mcam); -+ mmpcam_power_up_ctlr(cam); - return mccic_resume(&cam->mcam); - } - -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/mxl111sf.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/dvb/dvb-usb/mxl111sf.c -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/mxl111sf.c -@@ -340,7 +340,6 @@ static int mxl111sf_ep6_streaming_ctrl(s - struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv; - int ret = 0; -- u8 tmp; - - deb_info("%s(%d)\n", __func__, onoff); - -Index: linux-3.3.x86_64/drivers/media/video/gspca/ov534_9.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/gspca/ov534_9.c -+++ linux-3.3.x86_64/drivers/media/video/gspca/ov534_9.c -@@ -1107,16 +1107,34 @@ static void setbrightness(struct gspca_d - { - struct sd *sd = (struct sd *) gspca_dev; - u8 val; -+ s8 sval; - - if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) - return; -- val = sd->ctrls[BRIGHTNESS].val; -- if (val < 8) -- val = 15 - val; /* f .. 8 */ -- else -- val = val - 8; /* 0 .. 7 */ -- sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */ -- 0x0f | (val << 4)); -+ if (sd->sensor == SENSOR_OV562x) { -+ sval = sd->ctrls[BRIGHTNESS].val; -+ val = 0x76; -+ val += sval; -+ sccb_write(gspca_dev, 0x24, val); -+ val = 0x6a; -+ val += sval; -+ sccb_write(gspca_dev, 0x25, val); -+ if (sval < -40) -+ val = 0x71; -+ else if (sval < 20) -+ val = 0x94; -+ else -+ val = 0xe6; -+ sccb_write(gspca_dev, 0x26, val); -+ } else { -+ val = sd->ctrls[BRIGHTNESS].val; -+ if (val < 8) -+ val = 15 - val; /* f .. 8 */ -+ else -+ val = val - 8; /* 0 .. 7 */ -+ sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */ -+ 0x0f | (val << 4)); -+ } - } - - static void setcontrast(struct gspca_dev *gspca_dev) -@@ -1339,7 +1357,16 @@ static int sd_init(struct gspca_dev *gsp - reg_w(gspca_dev, 0x56, 0x17); - } else if ((sensor_id & 0xfff0) == 0x5620) { - sd->sensor = SENSOR_OV562x; -- -+ gspca_dev->ctrl_dis = (1 << CONTRAST) | -+ (1 << AUTOGAIN) | -+ (1 << EXPOSURE) | -+ (1 << SHARPNESS) | -+ (1 << SATUR) | -+ (1 << LIGHTFREQ); -+ -+ sd->ctrls[BRIGHTNESS].min = -90; -+ sd->ctrls[BRIGHTNESS].max = 90; -+ sd->ctrls[BRIGHTNESS].def = 0; - gspca_dev->cam.cam_mode = ov562x_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode); - -@@ -1360,8 +1387,12 @@ static int sd_start(struct gspca_dev *gs - { - struct sd *sd = (struct sd *) gspca_dev; - -- if (sd->sensor == SENSOR_OV971x || sd->sensor == SENSOR_OV562x) -+ if (sd->sensor == SENSOR_OV971x) - return gspca_dev->usb_err; -+ else if (sd->sensor == SENSOR_OV562x) { -+ setbrightness(gspca_dev); -+ return gspca_dev->usb_err; -+ } - switch (gspca_dev->curr_mode) { - case QVGA_MODE: /* 320x240 */ - sccb_w_array(gspca_dev, ov965x_start_1_vga, -Index: linux-3.3.x86_64/drivers/media/video/gspca/sn9c20x.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/gspca/sn9c20x.c -+++ linux-3.3.x86_64/drivers/media/video/gspca/sn9c20x.c -@@ -1,5 +1,7 @@ - /* - * Sonix sn9c201 sn9c202 library -+ * -+ * Copyright (C) 2012 Jean-Francois Moine - * Copyright (C) 2008-2009 microdia project - * Copyright (C) 2009 Brian Johnson - * -@@ -33,8 +35,6 @@ MODULE_AUTHOR("Brian Johnson dev; - int result; -+ -+ if (gspca_dev->usb_err < 0) -+ return; - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - 0x00, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, -@@ -1125,17 +1103,19 @@ static int reg_r(struct gspca_dev *gspca - length, - 500); - if (unlikely(result < 0 || result != length)) { -- pr_err("Read register failed 0x%02X\n", reg); -- return -EIO; -+ pr_err("Read register %02x failed %d\n", reg, result); -+ gspca_dev->usb_err = result; - } -- return 0; - } - --static int reg_w(struct gspca_dev *gspca_dev, u16 reg, -+static void reg_w(struct gspca_dev *gspca_dev, u16 reg, - const u8 *buffer, int length) - { - struct usb_device *dev = gspca_dev->dev; - int result; -+ -+ if (gspca_dev->usb_err < 0) -+ return; - memcpy(gspca_dev->usb_buf, buffer, length); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x08, -@@ -1146,38 +1126,41 @@ static int reg_w(struct gspca_dev *gspca - length, - 500); - if (unlikely(result < 0 || result != length)) { -- pr_err("Write register failed index 0x%02X\n", reg); -- return -EIO; -+ pr_err("Write register %02x failed %d\n", reg, result); -+ gspca_dev->usb_err = result; - } -- return 0; - } - --static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) -+static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value) - { -- u8 data[1] = {value}; -- return reg_w(gspca_dev, reg, data, 1); -+ reg_w(gspca_dev, reg, &value, 1); - } - --static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) -+static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer) - { - int i; -+ - reg_w(gspca_dev, 0x10c0, buffer, 8); - for (i = 0; i < 5; i++) { - reg_r(gspca_dev, 0x10c0, 1); -+ if (gspca_dev->usb_err < 0) -+ return; - if (gspca_dev->usb_buf[0] & 0x04) { -- if (gspca_dev->usb_buf[0] & 0x08) -- return -EIO; -- return 0; -+ if (gspca_dev->usb_buf[0] & 0x08) { -+ pr_err("i2c_w error\n"); -+ gspca_dev->usb_err = -EIO; -+ } -+ return; - } -- msleep(1); -+ msleep(10); - } -- return -EIO; -+ pr_err("i2c_w reg %02x no response\n", buffer[2]); -+/* gspca_dev->usb_err = -EIO; fixme: may occur */ - } - --static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) -+static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) - { - struct sd *sd = (struct sd *) gspca_dev; -- - u8 row[8]; - - /* -@@ -1193,10 +1176,19 @@ static int i2c_w1(struct gspca_dev *gspc - row[6] = 0x00; - row[7] = 0x10; - -- return i2c_w(gspca_dev, row); -+ i2c_w(gspca_dev, row); -+} -+ -+static void i2c_w1_buf(struct gspca_dev *gspca_dev, -+ struct i2c_reg_u8 *buf, int sz) -+{ -+ while (--sz >= 0) { -+ i2c_w1(gspca_dev, buf->reg, buf->val); -+ buf++; -+ } - } - --static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) -+static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) - { - struct sd *sd = (struct sd *) gspca_dev; - u8 row[8]; -@@ -1208,16 +1200,25 @@ static int i2c_w2(struct gspca_dev *gspc - row[0] = 0x81 | (3 << 4); - row[1] = sd->i2c_addr; - row[2] = reg; -- row[3] = (val >> 8) & 0xff; -- row[4] = val & 0xff; -+ row[3] = val >> 8; -+ row[4] = val; - row[5] = 0x00; - row[6] = 0x00; - row[7] = 0x10; - -- return i2c_w(gspca_dev, row); -+ i2c_w(gspca_dev, row); - } - --static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) -+static void i2c_w2_buf(struct gspca_dev *gspca_dev, -+ struct i2c_reg_u16 *buf, int sz) -+{ -+ while (--sz >= 0) { -+ i2c_w2(gspca_dev, buf->reg, buf->val); -+ buf++; -+ } -+} -+ -+static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) - { - struct sd *sd = (struct sd *) gspca_dev; - u8 row[8]; -@@ -1230,19 +1231,15 @@ static int i2c_r1(struct gspca_dev *gspc - row[5] = 0; - row[6] = 0; - row[7] = 0x10; -- if (i2c_w(gspca_dev, row) < 0) -- return -EIO; -+ i2c_w(gspca_dev, row); - row[0] = 0x81 | (1 << 4) | 0x02; - row[2] = 0; -- if (i2c_w(gspca_dev, row) < 0) -- return -EIO; -- if (reg_r(gspca_dev, 0x10c2, 5) < 0) -- return -EIO; -+ i2c_w(gspca_dev, row); -+ reg_r(gspca_dev, 0x10c2, 5); - *val = gspca_dev->usb_buf[4]; -- return 0; - } - --static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) -+static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) - { - struct sd *sd = (struct sd *) gspca_dev; - u8 row[8]; -@@ -1255,233 +1252,204 @@ static int i2c_r2(struct gspca_dev *gspc - row[5] = 0; - row[6] = 0; - row[7] = 0x10; -- if (i2c_w(gspca_dev, row) < 0) -- return -EIO; -+ i2c_w(gspca_dev, row); - row[0] = 0x81 | (2 << 4) | 0x02; - row[2] = 0; -- if (i2c_w(gspca_dev, row) < 0) -- return -EIO; -- if (reg_r(gspca_dev, 0x10c2, 5) < 0) -- return -EIO; -+ i2c_w(gspca_dev, row); -+ reg_r(gspca_dev, 0x10c2, 5); - *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4]; -- return 0; - } - --static int ov9650_init_sensor(struct gspca_dev *gspca_dev) -+static void ov9650_init_sensor(struct gspca_dev *gspca_dev) - { -- int i; - u16 id; - struct sd *sd = (struct sd *) gspca_dev; - -- if (i2c_r2(gspca_dev, 0x1c, &id) < 0) -- return -EINVAL; -+ i2c_r2(gspca_dev, 0x1c, &id); -+ if (gspca_dev->usb_err < 0) -+ return; - - if (id != 0x7fa2) { - pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id); -- return -ENODEV; -+ gspca_dev->usb_err = -ENODEV; -+ return; - } - -- for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) { -- if (i2c_w1(gspca_dev, ov9650_init[i].reg, -- ov9650_init[i].val) < 0) { -- pr_err("OV9650 sensor initialization failed\n"); -- return -ENODEV; -- } -- } -+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ -+ msleep(200); -+ i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("OV9650 sensor initialization failed\n"); - sd->hstart = 1; - sd->vstart = 7; -- return 0; - } - --static int ov9655_init_sensor(struct gspca_dev *gspca_dev) -+static void ov9655_init_sensor(struct gspca_dev *gspca_dev) - { -- int i; - struct sd *sd = (struct sd *) gspca_dev; - -- for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) { -- if (i2c_w1(gspca_dev, ov9655_init[i].reg, -- ov9655_init[i].val) < 0) { -- pr_err("OV9655 sensor initialization failed\n"); -- return -ENODEV; -- } -- } -+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ -+ msleep(200); -+ i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("OV9655 sensor initialization failed\n"); -+ - /* disable hflip and vflip */ -- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); -+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); - sd->hstart = 1; - sd->vstart = 2; -- return 0; - } - --static int soi968_init_sensor(struct gspca_dev *gspca_dev) -+static void soi968_init_sensor(struct gspca_dev *gspca_dev) - { -- int i; - struct sd *sd = (struct sd *) gspca_dev; - -- for (i = 0; i < ARRAY_SIZE(soi968_init); i++) { -- if (i2c_w1(gspca_dev, soi968_init[i].reg, -- soi968_init[i].val) < 0) { -- pr_err("SOI968 sensor initialization failed\n"); -- return -ENODEV; -- } -- } -+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ -+ msleep(200); -+ i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("SOI968 sensor initialization failed\n"); -+ - /* disable hflip and vflip */ -- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) -- | (1 << EXPOSURE_IDX); -+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP) -+ | (1 << EXPOSURE); - sd->hstart = 60; - sd->vstart = 11; -- return 0; - } - --static int ov7660_init_sensor(struct gspca_dev *gspca_dev) -+static void ov7660_init_sensor(struct gspca_dev *gspca_dev) - { -- int i; - struct sd *sd = (struct sd *) gspca_dev; - -- for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) { -- if (i2c_w1(gspca_dev, ov7660_init[i].reg, -- ov7660_init[i].val) < 0) { -- pr_err("OV7660 sensor initialization failed\n"); -- return -ENODEV; -- } -- } -+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ -+ msleep(200); -+ i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("OV7660 sensor initialization failed\n"); - sd->hstart = 3; - sd->vstart = 3; -- return 0; - } - --static int ov7670_init_sensor(struct gspca_dev *gspca_dev) -+static void ov7670_init_sensor(struct gspca_dev *gspca_dev) - { -- int i; - struct sd *sd = (struct sd *) gspca_dev; - -- for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) { -- if (i2c_w1(gspca_dev, ov7670_init[i].reg, -- ov7670_init[i].val) < 0) { -- pr_err("OV7670 sensor initialization failed\n"); -- return -ENODEV; -- } -- } -+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */ -+ msleep(200); -+ i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("OV7670 sensor initialization failed\n"); -+ - /* disable hflip and vflip */ -- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); -+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); - sd->hstart = 0; - sd->vstart = 1; -- return 0; - } - --static int mt9v_init_sensor(struct gspca_dev *gspca_dev) -+static void mt9v_init_sensor(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- int i; - u16 value; -- int ret; - - sd->i2c_addr = 0x5d; -- ret = i2c_r2(gspca_dev, 0xff, &value); -- if ((ret == 0) && (value == 0x8243)) { -- for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) { -- if (i2c_w2(gspca_dev, mt9v011_init[i].reg, -- mt9v011_init[i].val) < 0) { -- pr_err("MT9V011 sensor initialization failed\n"); -- return -ENODEV; -- } -+ i2c_r2(gspca_dev, 0xff, &value); -+ if (gspca_dev->usb_err >= 0 -+ && value == 0x8243) { -+ i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init)); -+ if (gspca_dev->usb_err < 0) { -+ pr_err("MT9V011 sensor initialization failed\n"); -+ return; - } - sd->hstart = 2; - sd->vstart = 2; - sd->sensor = SENSOR_MT9V011; - pr_info("MT9V011 sensor detected\n"); -- return 0; -+ return; - } - -+ gspca_dev->usb_err = 0; - sd->i2c_addr = 0x5c; - i2c_w2(gspca_dev, 0x01, 0x0004); -- ret = i2c_r2(gspca_dev, 0xff, &value); -- if ((ret == 0) && (value == 0x823a)) { -- for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) { -- if (i2c_w2(gspca_dev, mt9v111_init[i].reg, -- mt9v111_init[i].val) < 0) { -- pr_err("MT9V111 sensor initialization failed\n"); -- return -ENODEV; -- } -+ i2c_r2(gspca_dev, 0xff, &value); -+ if (gspca_dev->usb_err >= 0 -+ && value == 0x823a) { -+ i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init)); -+ if (gspca_dev->usb_err < 0) { -+ pr_err("MT9V111 sensor initialization failed\n"); -+ return; - } -- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) -- | (1 << AUTOGAIN_IDX) -- | (1 << GAIN_IDX); -+ gspca_dev->ctrl_dis = (1 << EXPOSURE) -+ | (1 << AUTOGAIN) -+ | (1 << GAIN); - sd->hstart = 2; - sd->vstart = 2; - sd->sensor = SENSOR_MT9V111; - pr_info("MT9V111 sensor detected\n"); -- return 0; -+ return; - } - -+ gspca_dev->usb_err = 0; - sd->i2c_addr = 0x5d; -- ret = i2c_w2(gspca_dev, 0xf0, 0x0000); -- if (ret < 0) { -+ i2c_w2(gspca_dev, 0xf0, 0x0000); -+ if (gspca_dev->usb_err < 0) { -+ gspca_dev->usb_err = 0; - sd->i2c_addr = 0x48; - i2c_w2(gspca_dev, 0xf0, 0x0000); - } -- ret = i2c_r2(gspca_dev, 0x00, &value); -- if ((ret == 0) && (value == 0x1229)) { -- for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) { -- if (i2c_w2(gspca_dev, mt9v112_init[i].reg, -- mt9v112_init[i].val) < 0) { -- pr_err("MT9V112 sensor initialization failed\n"); -- return -ENODEV; -- } -+ i2c_r2(gspca_dev, 0x00, &value); -+ if (gspca_dev->usb_err >= 0 -+ && value == 0x1229) { -+ i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init)); -+ if (gspca_dev->usb_err < 0) { -+ pr_err("MT9V112 sensor initialization failed\n"); -+ return; - } - sd->hstart = 6; - sd->vstart = 2; - sd->sensor = SENSOR_MT9V112; - pr_info("MT9V112 sensor detected\n"); -- return 0; -+ return; - } - -- return -ENODEV; -+ gspca_dev->usb_err = -ENODEV; - } - --static int mt9m112_init_sensor(struct gspca_dev *gspca_dev) -+static void mt9m112_init_sensor(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- int i; -- for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) { -- if (i2c_w2(gspca_dev, mt9m112_init[i].reg, -- mt9m112_init[i].val) < 0) { -- pr_err("MT9M112 sensor initialization failed\n"); -- return -ENODEV; -- } -- } -- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) -- | (1 << GAIN_IDX); -+ -+ i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("MT9M112 sensor initialization failed\n"); -+ -+ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) -+ | (1 << GAIN); - sd->hstart = 0; - sd->vstart = 2; -- return 0; - } - --static int mt9m111_init_sensor(struct gspca_dev *gspca_dev) -+static void mt9m111_init_sensor(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- int i; -- for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) { -- if (i2c_w2(gspca_dev, mt9m111_init[i].reg, -- mt9m111_init[i].val) < 0) { -- pr_err("MT9M111 sensor initialization failed\n"); -- return -ENODEV; -- } -- } -- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) -- | (1 << GAIN_IDX); -+ -+ i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("MT9M111 sensor initialization failed\n"); -+ -+ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) -+ | (1 << GAIN); - sd->hstart = 0; - sd->vstart = 2; -- return 0; - } - --static int mt9m001_init_sensor(struct gspca_dev *gspca_dev) -+static void mt9m001_init_sensor(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- int i; - u16 id; - -- if (i2c_r2(gspca_dev, 0x00, &id) < 0) -- return -EINVAL; -+ i2c_r2(gspca_dev, 0x00, &id); -+ if (gspca_dev->usb_err < 0) -+ return; - - /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ - switch (id) { -@@ -1494,85 +1462,78 @@ static int mt9m001_init_sensor(struct gs - break; - default: - pr_err("No MT9M001 chip detected, ID = %x\n\n", id); -- return -ENODEV; -+ gspca_dev->usb_err = -ENODEV; -+ return; - } - -- for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) { -- if (i2c_w2(gspca_dev, mt9m001_init[i].reg, -- mt9m001_init[i].val) < 0) { -- pr_err("MT9M001 sensor initialization failed\n"); -- return -ENODEV; -- } -- } -+ i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("MT9M001 sensor initialization failed\n"); -+ - /* disable hflip and vflip */ -- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); -+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); - sd->hstart = 1; - sd->vstart = 1; -- return 0; - } - --static int hv7131r_init_sensor(struct gspca_dev *gspca_dev) -+static void hv7131r_init_sensor(struct gspca_dev *gspca_dev) - { -- int i; - struct sd *sd = (struct sd *) gspca_dev; - -- for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) { -- if (i2c_w1(gspca_dev, hv7131r_init[i].reg, -- hv7131r_init[i].val) < 0) { -- pr_err("HV7131R Sensor initialization failed\n"); -- return -ENODEV; -- } -- } -+ i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init)); -+ if (gspca_dev->usb_err < 0) -+ pr_err("HV7131R Sensor initialization failed\n"); -+ - sd->hstart = 0; - sd->vstart = 1; -- return 0; - } - --static int set_cmatrix(struct gspca_dev *gspca_dev) -+static void set_cmatrix(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- s32 hue_coord, hue_index = 180 + sd->hue; -+ int satur; -+ s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val; - u8 cmatrix[21]; - - memset(cmatrix, 0, sizeof cmatrix); -- cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26; -+ cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26; - cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; - cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; -- cmatrix[18] = sd->brightness - 0x80; -+ cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80; - -- hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8; -+ satur = sd->ctrls[SATURATION].val; -+ hue_coord = (hsv_red_x[hue_index] * satur) >> 8; - cmatrix[6] = hue_coord; - cmatrix[7] = (hue_coord >> 8) & 0x0f; - -- hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8; -+ hue_coord = (hsv_red_y[hue_index] * satur) >> 8; - cmatrix[8] = hue_coord; - cmatrix[9] = (hue_coord >> 8) & 0x0f; - -- hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8; -+ hue_coord = (hsv_green_x[hue_index] * satur) >> 8; - cmatrix[10] = hue_coord; - cmatrix[11] = (hue_coord >> 8) & 0x0f; - -- hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8; -+ hue_coord = (hsv_green_y[hue_index] * satur) >> 8; - cmatrix[12] = hue_coord; - cmatrix[13] = (hue_coord >> 8) & 0x0f; - -- hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8; -+ hue_coord = (hsv_blue_x[hue_index] * satur) >> 8; - cmatrix[14] = hue_coord; - cmatrix[15] = (hue_coord >> 8) & 0x0f; - -- hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8; -+ hue_coord = (hsv_blue_y[hue_index] * satur) >> 8; - cmatrix[16] = hue_coord; - cmatrix[17] = (hue_coord >> 8) & 0x0f; - -- return reg_w(gspca_dev, 0x10e1, cmatrix, 21); -+ reg_w(gspca_dev, 0x10e1, cmatrix, 21); - } - --static int set_gamma(struct gspca_dev *gspca_dev) -+static void set_gamma(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; - u8 gamma[17]; -- u8 gval = sd->gamma * 0xb8 / 0x100; -- -+ u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100; - - gamma[0] = 0x0a; - gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); -@@ -1592,29 +1553,29 @@ static int set_gamma(struct gspca_dev *g - gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8); - gamma[16] = 0xf5; - -- return reg_w(gspca_dev, 0x1190, gamma, 17); -+ reg_w(gspca_dev, 0x1190, gamma, 17); - } - --static int set_redblue(struct gspca_dev *gspca_dev) -+static void set_redblue(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- reg_w1(gspca_dev, 0x118c, sd->red); -- reg_w1(gspca_dev, 0x118f, sd->blue); -- return 0; -+ -+ reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val); -+ reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val); - } - --static int set_hvflip(struct gspca_dev *gspca_dev) -+static void set_hvflip(struct gspca_dev *gspca_dev) - { - u8 value, tslb, hflip, vflip; - u16 value2; - struct sd *sd = (struct sd *) gspca_dev; - - if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { -- hflip = !sd->hflip; -- vflip = !sd->vflip; -+ hflip = !sd->ctrls[HFLIP].val; -+ vflip = !sd->ctrls[VFLIP].val; - } else { -- hflip = sd->hflip; -- vflip = sd->vflip; -+ hflip = sd->ctrls[HFLIP].val; -+ vflip = sd->ctrls[VFLIP].val; - } - - switch (sd->sensor) { -@@ -1625,8 +1586,9 @@ static int set_hvflip(struct gspca_dev * - if (vflip) { - value |= 0x10; - sd->vstart = 2; -- } else -+ } else { - sd->vstart = 3; -+ } - reg_w1(gspca_dev, 0x1182, sd->vstart); - i2c_w1(gspca_dev, 0x1e, value); - break; -@@ -1674,13 +1636,15 @@ static int set_hvflip(struct gspca_dev * - i2c_w1(gspca_dev, 0x01, value); - break; - } -- return 0; - } - --static int set_exposure(struct gspca_dev *gspca_dev) -+static void set_exposure(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; - u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e}; -+ int expo; -+ -+ expo = sd->ctrls[EXPOSURE].val; - switch (sd->sensor) { - case SENSOR_OV7660: - case SENSOR_OV7670: -@@ -1688,35 +1652,37 @@ static int set_exposure(struct gspca_dev - case SENSOR_OV9650: - exp[0] |= (3 << 4); - exp[2] = 0x2d; -- exp[3] = sd->exposure & 0xff; -- exp[4] = sd->exposure >> 8; -+ exp[3] = expo; -+ exp[4] = expo >> 8; - break; - case SENSOR_MT9M001: - case SENSOR_MT9V112: - case SENSOR_MT9V011: - exp[0] |= (3 << 4); - exp[2] = 0x09; -- exp[3] = sd->exposure >> 8; -- exp[4] = sd->exposure & 0xff; -+ exp[3] = expo >> 8; -+ exp[4] = expo; - break; - case SENSOR_HV7131R: - exp[0] |= (4 << 4); - exp[2] = 0x25; -- exp[3] = (sd->exposure >> 5) & 0xff; -- exp[4] = (sd->exposure << 3) & 0xff; -+ exp[3] = expo >> 5; -+ exp[4] = expo << 3; - exp[5] = 0; - break; - default: -- return 0; -+ return; - } - i2c_w(gspca_dev, exp); -- return 0; - } - --static int set_gain(struct gspca_dev *gspca_dev) -+static void set_gain(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; - u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; -+ int g; -+ -+ g = sd->ctrls[GAIN].val; - switch (sd->sensor) { - case SENSOR_OV7660: - case SENSOR_OV7670: -@@ -1724,238 +1690,50 @@ static int set_gain(struct gspca_dev *gs - case SENSOR_OV9655: - case SENSOR_OV9650: - gain[0] |= (2 << 4); -- gain[3] = ov_gain[sd->gain]; -+ gain[3] = ov_gain[g]; - break; - case SENSOR_MT9V011: - gain[0] |= (3 << 4); - gain[2] = 0x35; -- gain[3] = micron1_gain[sd->gain] >> 8; -- gain[4] = micron1_gain[sd->gain] & 0xff; -+ gain[3] = micron1_gain[g] >> 8; -+ gain[4] = micron1_gain[g]; - break; - case SENSOR_MT9V112: - gain[0] |= (3 << 4); - gain[2] = 0x2f; -- gain[3] = micron1_gain[sd->gain] >> 8; -- gain[4] = micron1_gain[sd->gain] & 0xff; -+ gain[3] = micron1_gain[g] >> 8; -+ gain[4] = micron1_gain[g]; - break; - case SENSOR_MT9M001: - gain[0] |= (3 << 4); - gain[2] = 0x2f; -- gain[3] = micron2_gain[sd->gain] >> 8; -- gain[4] = micron2_gain[sd->gain] & 0xff; -+ gain[3] = micron2_gain[g] >> 8; -+ gain[4] = micron2_gain[g]; - break; - case SENSOR_HV7131R: - gain[0] |= (2 << 4); - gain[2] = 0x30; -- gain[3] = hv7131r_gain[sd->gain]; -+ gain[3] = hv7131r_gain[g]; - break; - default: -- return 0; -+ return; - } - i2c_w(gspca_dev, gain); -- return 0; --} -- --static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->brightness = val; -- if (gspca_dev->streaming) -- return set_cmatrix(gspca_dev); -- return 0; --} -- --static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->brightness; -- return 0; --} -- -- --static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->contrast = val; -- if (gspca_dev->streaming) -- return set_cmatrix(gspca_dev); -- return 0; --} -- --static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->contrast; -- return 0; --} -- --static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->saturation = val; -- if (gspca_dev->streaming) -- return set_cmatrix(gspca_dev); -- return 0; --} -- --static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->saturation; -- return 0; --} -- --static int sd_sethue(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->hue = val; -- if (gspca_dev->streaming) -- return set_cmatrix(gspca_dev); -- return 0; --} -- --static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->hue; -- return 0; --} -- --static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->gamma = val; -- if (gspca_dev->streaming) -- return set_gamma(gspca_dev); -- return 0; --} -- --static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->gamma; -- return 0; --} -- --static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->red = val; -- if (gspca_dev->streaming) -- return set_redblue(gspca_dev); -- return 0; --} -- --static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->red; -- return 0; --} -- --static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->blue = val; -- if (gspca_dev->streaming) -- return set_redblue(gspca_dev); -- return 0; --} -- --static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->blue; -- return 0; --} -- --static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->hflip = val; -- if (gspca_dev->streaming) -- return set_hvflip(gspca_dev); -- return 0; --} -- --static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->hflip; -- return 0; --} -- --static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->vflip = val; -- if (gspca_dev->streaming) -- return set_hvflip(gspca_dev); -- return 0; --} -- --static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->vflip; -- return 0; --} -- --static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->exposure = val; -- if (gspca_dev->streaming) -- return set_exposure(gspca_dev); -- return 0; --} -- --static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->exposure; -- return 0; --} -- --static int sd_setgain(struct gspca_dev *gspca_dev, s32 val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- -- sd->gain = val; -- if (gspca_dev->streaming) -- return set_gain(gspca_dev); -- return 0; --} -- --static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->gain; -- return 0; - } - --static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val) -+static void set_quality(struct gspca_dev *gspca_dev) - { - struct sd *sd = (struct sd *) gspca_dev; -- sd->auto_exposure = val; -- return 0; --} - --static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val) --{ -- struct sd *sd = (struct sd *) gspca_dev; -- *val = sd->auto_exposure; -- return 0; -+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); -+ reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */ -+ reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */ -+ reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); -+ reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); -+ reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */ -+ reg_w1(gspca_dev, 0x10e0, sd->fmt); -+ sd->fmt ^= 0x0c; /* invert QTAB use + write */ -+ reg_w1(gspca_dev, 0x10e0, sd->fmt); - } - - #ifdef CONFIG_VIDEO_ADV_DEBUG -@@ -1963,28 +1741,26 @@ static int sd_dbg_g_register(struct gspc - struct v4l2_dbg_register *reg) - { - struct sd *sd = (struct sd *) gspca_dev; -+ - switch (reg->match.type) { - case V4L2_CHIP_MATCH_HOST: - if (reg->match.addr != 0) - return -EINVAL; - if (reg->reg < 0x1000 || reg->reg > 0x11ff) - return -EINVAL; -- if (reg_r(gspca_dev, reg->reg, 1) < 0) -- return -EINVAL; -+ reg_r(gspca_dev, reg->reg, 1); - reg->val = gspca_dev->usb_buf[0]; -- return 0; -+ return gspca_dev->usb_err; - case V4L2_CHIP_MATCH_I2C_ADDR: - if (reg->match.addr != sd->i2c_addr) - return -EINVAL; - if (sd->sensor >= SENSOR_MT9V011 && - sd->sensor <= SENSOR_MT9M112) { -- if (i2c_r2(gspca_dev, reg->reg, (u16 *)®->val) < 0) -- return -EINVAL; -+ i2c_r2(gspca_dev, reg->reg, (u16 *) ®->val); - } else { -- if (i2c_r1(gspca_dev, reg->reg, (u8 *)®->val) < 0) -- return -EINVAL; -+ i2c_r1(gspca_dev, reg->reg, (u8 *) ®->val); - } -- return 0; -+ return gspca_dev->usb_err; - } - return -EINVAL; - } -@@ -1993,27 +1769,25 @@ static int sd_dbg_s_register(struct gspc - struct v4l2_dbg_register *reg) - { - struct sd *sd = (struct sd *) gspca_dev; -+ - switch (reg->match.type) { - case V4L2_CHIP_MATCH_HOST: - if (reg->match.addr != 0) - return -EINVAL; - if (reg->reg < 0x1000 || reg->reg > 0x11ff) - return -EINVAL; -- if (reg_w1(gspca_dev, reg->reg, reg->val) < 0) -- return -EINVAL; -- return 0; -+ reg_w1(gspca_dev, reg->reg, reg->val); -+ return gspca_dev->usb_err; - case V4L2_CHIP_MATCH_I2C_ADDR: - if (reg->match.addr != sd->i2c_addr) - return -EINVAL; - if (sd->sensor >= SENSOR_MT9V011 && - sd->sensor <= SENSOR_MT9M112) { -- if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0) -- return -EINVAL; -+ i2c_w2(gspca_dev, reg->reg, reg->val); - } else { -- if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0) -- return -EINVAL; -+ i2c_w1(gspca_dev, reg->reg, reg->val); - } -- return 0; -+ return gspca_dev->usb_err; - } - return -EINVAL; - } -@@ -2050,9 +1824,9 @@ static int sd_config(struct gspca_dev *g - cam = &gspca_dev->cam; - cam->needs_full_bandwidth = 1; - -- sd->sensor = (id->driver_info >> 8) & 0xff; -- sd->i2c_addr = id->driver_info & 0xff; -- sd->flags = (id->driver_info >> 16) & 0xff; -+ sd->sensor = id->driver_info >> 8; -+ sd->i2c_addr = id->driver_info; -+ sd->flags = id->driver_info >> 16; - - switch (sd->sensor) { - case SENSOR_MT9M112: -@@ -2076,21 +1850,9 @@ static int sd_config(struct gspca_dev *g - sd->older_step = 0; - sd->exposure_step = 16; - -- sd->brightness = BRIGHTNESS_DEFAULT; -- sd->contrast = CONTRAST_DEFAULT; -- sd->saturation = SATURATION_DEFAULT; -- sd->hue = HUE_DEFAULT; -- sd->gamma = GAMMA_DEFAULT; -- sd->red = RED_DEFAULT; -- sd->blue = BLUE_DEFAULT; -- -- sd->hflip = HFLIP_DEFAULT; -- sd->vflip = VFLIP_DEFAULT; -- sd->exposure = EXPOSURE_DEFAULT; -- sd->gain = GAIN_DEFAULT; -- sd->auto_exposure = AUTO_EXPOSURE_DEFAULT; -+ gspca_dev->cam.ctrls = sd->ctrls; - -- sd->quality = 95; -+ INIT_WORK(&sd->work, qual_upd); - - return 0; - } -@@ -2105,9 +1867,10 @@ static int sd_init(struct gspca_dev *gsp - - for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { - value = bridge_init[i][1]; -- if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) { -+ reg_w(gspca_dev, bridge_init[i][0], &value, 1); -+ if (gspca_dev->usb_err < 0) { - pr_err("Device initialization failed\n"); -- return -ENODEV; -+ return gspca_dev->usb_err; - } - } - -@@ -2116,72 +1879,85 @@ static int sd_init(struct gspca_dev *gsp - else - reg_w1(gspca_dev, 0x1006, 0x20); - -- if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) { -+ reg_w(gspca_dev, 0x10c0, i2c_init, 9); -+ if (gspca_dev->usb_err < 0) { - pr_err("Device initialization failed\n"); -- return -ENODEV; -+ return gspca_dev->usb_err; - } - - switch (sd->sensor) { - case SENSOR_OV9650: -- if (ov9650_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ ov9650_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - pr_info("OV9650 sensor detected\n"); - break; - case SENSOR_OV9655: -- if (ov9655_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ ov9655_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - pr_info("OV9655 sensor detected\n"); - break; - case SENSOR_SOI968: -- if (soi968_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ soi968_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - pr_info("SOI968 sensor detected\n"); - break; - case SENSOR_OV7660: -- if (ov7660_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ ov7660_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - pr_info("OV7660 sensor detected\n"); - break; - case SENSOR_OV7670: -- if (ov7670_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ ov7670_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - pr_info("OV7670 sensor detected\n"); - break; - case SENSOR_MT9VPRB: -- if (mt9v_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ mt9v_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; -+ pr_info("MT9VPRB sensor detected\n"); - break; - case SENSOR_MT9M111: -- if (mt9m111_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ mt9m111_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - pr_info("MT9M111 sensor detected\n"); - break; - case SENSOR_MT9M112: -- if (mt9m112_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ mt9m112_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - pr_info("MT9M112 sensor detected\n"); - break; - case SENSOR_MT9M001: -- if (mt9m001_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ mt9m001_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - break; - case SENSOR_HV7131R: -- if (hv7131r_init_sensor(gspca_dev) < 0) -- return -ENODEV; -+ hv7131r_init_sensor(gspca_dev); -+ if (gspca_dev->usb_err < 0) -+ break; - pr_info("HV7131R sensor detected\n"); - break; - default: -- pr_info("Unsupported Sensor\n"); -- return -ENODEV; -+ pr_err("Unsupported sensor\n"); -+ gspca_dev->usb_err = -ENODEV; - } - -- return 0; -+ return gspca_dev->usb_err; - } - - static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) - { - struct sd *sd = (struct sd *) gspca_dev; - u8 value; -+ - switch (sd->sensor) { - case SENSOR_SOI968: - if (mode & MODE_SXGA) { -@@ -2264,6 +2040,7 @@ static int sd_isoc_init(struct gspca_dev - break; - default: /* >= 640x480 */ - gspca_dev->alt = 9; -+ break; - } - } - -@@ -2290,14 +2067,15 @@ static int sd_start(struct gspca_dev *gs - - jpeg_define(sd->jpeg_hdr, height, width, - 0x21); -- jpeg_set_qual(sd->jpeg_hdr, sd->quality); -+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); - - if (mode & MODE_RAW) - fmt = 0x2d; - else if (mode & MODE_JPEG) -- fmt = 0x2c; -+ fmt = 0x24; - else - fmt = 0x2f; /* YUV 420 */ -+ sd->fmt = fmt; - - switch (mode & SCALE_MASK) { - case SCALE_1280x1024: -@@ -2334,18 +2112,37 @@ static int sd_start(struct gspca_dev *gs - set_hvflip(gspca_dev); - - reg_w1(gspca_dev, 0x1007, 0x20); -+ reg_w1(gspca_dev, 0x1061, 0x03); - -- reg_r(gspca_dev, 0x1061, 1); -- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02); -- return 0; -+ /* if JPEG, prepare the compression quality update */ -+ if (mode & MODE_JPEG) { -+ sd->pktsz = sd->npkt = 0; -+ sd->nchg = 0; -+ sd->work_thread = -+ create_singlethread_workqueue(KBUILD_MODNAME); -+ } -+ -+ return gspca_dev->usb_err; - } - - static void sd_stopN(struct gspca_dev *gspca_dev) - { - reg_w1(gspca_dev, 0x1007, 0x00); -+ reg_w1(gspca_dev, 0x1061, 0x01); -+} - -- reg_r(gspca_dev, 0x1061, 1); -- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02); -+/* called on streamoff with alt==0 and on disconnect */ -+/* the usb_lock is held at entry - restore on exit */ -+static void sd_stop0(struct gspca_dev *gspca_dev) -+{ -+ struct sd *sd = (struct sd *) gspca_dev; -+ -+ if (sd->work_thread != NULL) { -+ mutex_unlock(&gspca_dev->usb_lock); -+ destroy_workqueue(sd->work_thread); -+ mutex_lock(&gspca_dev->usb_lock); -+ sd->work_thread = NULL; -+ } - } - - static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) -@@ -2359,15 +2156,15 @@ static void do_autoexposure(struct gspca - * and exposure steps - */ - if (avg_lum < MIN_AVG_LUM) { -- if (sd->exposure > 0x1770) -+ if (sd->ctrls[EXPOSURE].val > 0x1770) - return; - -- new_exp = sd->exposure + sd->exposure_step; -+ new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step; - if (new_exp > 0x1770) - new_exp = 0x1770; - if (new_exp < 0x10) - new_exp = 0x10; -- sd->exposure = new_exp; -+ sd->ctrls[EXPOSURE].val = new_exp; - set_exposure(gspca_dev); - - sd->older_step = sd->old_step; -@@ -2379,14 +2176,14 @@ static void do_autoexposure(struct gspca - sd->exposure_step += 2; - } - if (avg_lum > MAX_AVG_LUM) { -- if (sd->exposure < 0x10) -+ if (sd->ctrls[EXPOSURE].val < 0x10) - return; -- new_exp = sd->exposure - sd->exposure_step; -+ new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step; - if (new_exp > 0x1700) - new_exp = 0x1770; - if (new_exp < 0x10) - new_exp = 0x10; -- sd->exposure = new_exp; -+ sd->ctrls[EXPOSURE].val = new_exp; - set_exposure(gspca_dev); - sd->older_step = sd->old_step; - sd->old_step = 0; -@@ -2403,14 +2200,14 @@ static void do_autogain(struct gspca_dev - struct sd *sd = (struct sd *) gspca_dev; - - if (avg_lum < MIN_AVG_LUM) { -- if (sd->gain + 1 <= 28) { -- sd->gain++; -+ if (sd->ctrls[GAIN].val + 1 <= 28) { -+ sd->ctrls[GAIN].val++; - set_gain(gspca_dev); - } - } - if (avg_lum > MAX_AVG_LUM) { -- if (sd->gain > 0) { -- sd->gain--; -+ if (sd->ctrls[GAIN].val > 0) { -+ sd->ctrls[GAIN].val--; - set_gain(gspca_dev); - } - } -@@ -2421,7 +2218,7 @@ static void sd_dqcallback(struct gspca_d - struct sd *sd = (struct sd *) gspca_dev; - int avg_lum; - -- if (!sd->auto_exposure) -+ if (!sd->ctrls[AUTOGAIN].val) - return; - - avg_lum = atomic_read(&sd->avg_lum); -@@ -2431,33 +2228,92 @@ static void sd_dqcallback(struct gspca_d - do_autoexposure(gspca_dev, avg_lum); - } - -+/* JPEG quality update */ -+/* This function is executed from a work queue. */ -+static void qual_upd(struct work_struct *work) -+{ -+ struct sd *sd = container_of(work, struct sd, work); -+ struct gspca_dev *gspca_dev = &sd->gspca_dev; -+ -+ mutex_lock(&gspca_dev->usb_lock); -+ PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val); -+ set_quality(gspca_dev); -+ mutex_unlock(&gspca_dev->usb_lock); -+} -+ - #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* interrupt packet */ - int len) /* interrupt packet length */ - { - struct sd *sd = (struct sd *) gspca_dev; -- int ret = -EINVAL; -+ - if (!(sd->flags & HAS_NO_BUTTON) && len == 1) { -- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); -- input_sync(gspca_dev->input_dev); -- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); -- input_sync(gspca_dev->input_dev); -- ret = 0; -+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); -+ input_sync(gspca_dev->input_dev); -+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); -+ input_sync(gspca_dev->input_dev); -+ return 0; - } -- return ret; -+ return -EINVAL; - } - #endif - -+/* check the JPEG compression */ -+static void transfer_check(struct gspca_dev *gspca_dev, -+ u8 *data) -+{ -+ struct sd *sd = (struct sd *) gspca_dev; -+ int new_qual, r; -+ -+ new_qual = 0; -+ -+ /* if USB error, discard the frame and decrease the quality */ -+ if (data[6] & 0x08) { /* USB FIFO full */ -+ gspca_dev->last_packet_type = DISCARD_PACKET; -+ new_qual = -5; -+ } else { -+ -+ /* else, compute the filling rate and a new JPEG quality */ -+ r = (sd->pktsz * 100) / -+ (sd->npkt * -+ gspca_dev->urb[0]->iso_frame_desc[0].length); -+ if (r >= 85) -+ new_qual = -3; -+ else if (r < 75) -+ new_qual = 2; -+ } -+ if (new_qual != 0) { -+ sd->nchg += new_qual; -+ if (sd->nchg < -6 || sd->nchg >= 12) { -+ sd->nchg = 0; -+ new_qual += sd->ctrls[QUALITY].val; -+ if (new_qual < QUALITY_MIN) -+ new_qual = QUALITY_MIN; -+ else if (new_qual > QUALITY_MAX) -+ new_qual = QUALITY_MAX; -+ if (new_qual != sd->ctrls[QUALITY].val) { -+ sd->ctrls[QUALITY].val = new_qual; -+ queue_work(sd->work_thread, &sd->work); -+ } -+ } -+ } else { -+ sd->nchg = 0; -+ } -+ sd->pktsz = sd->npkt = 0; -+} -+ - static void sd_pkt_scan(struct gspca_dev *gspca_dev, - u8 *data, /* isoc packet */ - int len) /* iso packet length */ - { - struct sd *sd = (struct sd *) gspca_dev; -- int avg_lum; -+ int avg_lum, is_jpeg; - static u8 frame_header[] = - {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; -- if (len == 64 && memcmp(data, frame_header, 6) == 0) { -+ -+ is_jpeg = (sd->fmt & 0x03) == 0; -+ if (len >= 64 && memcmp(data, frame_header, 6) == 0) { - avg_lum = ((data[35] >> 2) & 3) | - (data[20] << 2) | - (data[19] << 10); -@@ -2484,12 +2340,18 @@ static void sd_pkt_scan(struct gspca_dev - (data[33] << 10); - avg_lum >>= 9; - atomic_set(&sd->avg_lum, avg_lum); -+ -+ if (is_jpeg) -+ transfer_check(gspca_dev, data); -+ - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); -- return; -+ len -= 64; -+ if (len == 0) -+ return; -+ data += 64; - } - if (gspca_dev->last_packet_type == LAST_PACKET) { -- if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv -- & MODE_JPEG) { -+ if (is_jpeg) { - gspca_frame_add(gspca_dev, FIRST_PACKET, - sd->jpeg_hdr, JPEG_HDR_SZ); - gspca_frame_add(gspca_dev, INTER_PACKET, -@@ -2499,13 +2361,18 @@ static void sd_pkt_scan(struct gspca_dev - data, len); - } - } else { -+ /* if JPEG, count the packets and their size */ -+ if (is_jpeg) { -+ sd->npkt++; -+ sd->pktsz += len; -+ } - gspca_frame_add(gspca_dev, INTER_PACKET, data, len); - } - } - - /* sub-driver description */ - static const struct sd_desc sd_desc = { -- .name = MODULE_NAME, -+ .name = KBUILD_MODNAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .config = sd_config, -@@ -2513,6 +2380,7 @@ static const struct sd_desc sd_desc = { - .isoc_init = sd_isoc_init, - .start = sd_start, - .stopN = sd_stopN, -+ .stop0 = sd_stop0, - .pkt_scan = sd_pkt_scan, - #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) - .int_pkt_scan = sd_int_pkt_scan, -@@ -2581,7 +2449,7 @@ static int sd_probe(struct usb_interface - } - - static struct usb_driver sd_driver = { -- .name = MODULE_NAME, -+ .name = KBUILD_MODNAME, - .id_table = device_table, - .probe = sd_probe, - .disconnect = gspca_disconnect, -Index: linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-udma.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/ivtv/ivtv-udma.c -+++ linux-3.3.x86_64/drivers/media/video/ivtv/ivtv-udma.c -@@ -57,9 +57,9 @@ int ivtv_udma_fill_sg_list (struct ivtv_ - if (dma->bouncemap[map_offset] == NULL) - return -1; - local_irq_save(flags); -- src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; -+ src = kmap_atomic(dma->map[map_offset]) + offset; - memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); -- kunmap_atomic(src, KM_BOUNCE_READ); -+ kunmap_atomic(src); - local_irq_restore(flags); - sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset], len, offset); - } -Index: linux-3.3.x86_64/drivers/media/video/videobuf2-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/videobuf2-core.c -+++ linux-3.3.x86_64/drivers/media/video/videobuf2-core.c -@@ -19,6 +19,9 @@ - #include - #include - -+#include -+#include -+#include - #include - - static int debug; -@@ -1642,32 +1645,46 @@ static int __vb2_cleanup_fileio(struct v - * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor - * will be reported as available for writing. - * -+ * If the driver uses struct v4l2_fh, then vb2_poll() will also check for any -+ * pending events. -+ * - * The return values from this function are intended to be directly returned - * from poll handler in driver. - */ - unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) - { -- unsigned long flags; -- unsigned int ret; -+ struct video_device *vfd = video_devdata(file); -+ unsigned long req_events = poll_requested_events(wait); - struct vb2_buffer *vb = NULL; -+ unsigned int res = 0; -+ unsigned long flags; -+ -+ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { -+ struct v4l2_fh *fh = file->private_data; -+ -+ if (v4l2_event_pending(fh)) -+ res = POLLPRI; -+ else if (req_events & POLLPRI) -+ poll_wait(file, &fh->wait, wait); -+ } - - /* - * Start file I/O emulator only if streaming API has not been used yet. - */ - if (q->num_buffers == 0 && q->fileio == NULL) { -- if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ)) { -- ret = __vb2_init_fileio(q, 1); -- if (ret) -- return POLLERR; -+ if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) && -+ (req_events & (POLLIN | POLLRDNORM))) { -+ if (__vb2_init_fileio(q, 1)) -+ return res | POLLERR; - } -- if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE)) { -- ret = __vb2_init_fileio(q, 0); -- if (ret) -- return POLLERR; -+ if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) && -+ (req_events & (POLLOUT | POLLWRNORM))) { -+ if (__vb2_init_fileio(q, 0)) -+ return res | POLLERR; - /* - * Write to OUTPUT queue can be done immediately. - */ -- return POLLOUT | POLLWRNORM; -+ return res | POLLOUT | POLLWRNORM; - } - } - -@@ -1675,7 +1692,7 @@ unsigned int vb2_poll(struct vb2_queue * - * There is nothing to wait for if no buffers have already been queued. - */ - if (list_empty(&q->queued_list)) -- return POLLERR; -+ return res | POLLERR; - - poll_wait(file, &q->done_wq, wait); - -@@ -1690,10 +1707,11 @@ unsigned int vb2_poll(struct vb2_queue * - - if (vb && (vb->state == VB2_BUF_STATE_DONE - || vb->state == VB2_BUF_STATE_ERROR)) { -- return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM : -- POLLIN | POLLRDNORM; -+ return (V4L2_TYPE_IS_OUTPUT(q->type)) ? -+ res | POLLOUT | POLLWRNORM : -+ res | POLLIN | POLLRDNORM; - } -- return 0; -+ return res; - } - EXPORT_SYMBOL_GPL(vb2_poll); - -Index: linux-3.3.x86_64/drivers/media/video/videobuf-core.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/videobuf-core.c -+++ linux-3.3.x86_64/drivers/media/video/videobuf-core.c -@@ -1129,6 +1129,7 @@ unsigned int videobuf_poll_stream(struct - struct videobuf_queue *q, - poll_table *wait) - { -+ unsigned long req_events = poll_requested_events(wait); - struct videobuf_buffer *buf = NULL; - unsigned int rc = 0; - -@@ -1137,7 +1138,7 @@ unsigned int videobuf_poll_stream(struct - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, - struct videobuf_buffer, stream); -- } else { -+ } else if (req_events & (POLLIN | POLLRDNORM)) { - if (!q->reading) - __videobuf_read_start(q); - if (!q->reading) { -Index: linux-3.3.x86_64/drivers/media/video/pwc/pwc-if.c -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/video/pwc/pwc-if.c -+++ linux-3.3.x86_64/drivers/media/video/pwc/pwc-if.c -@@ -625,10 +625,19 @@ static ssize_t pwc_video_read(struct fil - static unsigned int pwc_video_poll(struct file *file, poll_table *wait) - { - struct pwc_device *pdev = video_drvdata(file); -+ unsigned long req_events = poll_requested_events(wait); - - if (!pdev->udev) - return POLL_ERR; - -+ if ((req_events & (POLLIN | POLLRDNORM)) && -+ pdev->vb_queue.num_buffers == 0 && -+ !pdev->iso_init) { -+ /* This poll will start a read stream, check capt_file */ -+ if (pwc_test_n_set_capt_file(pdev, file)) -+ return POLL_ERR; -+ } -+ - return vb2_poll(&pdev->vb_queue, file, wait); - } - -Index: linux-3.3.x86_64/drivers/media/common/tuners/Kconfig -=================================================================== ---- linux-3.3.x86_64.orig/drivers/media/common/tuners/Kconfig -+++ linux-3.3.x86_64/drivers/media/common/tuners/Kconfig -@@ -204,6 +204,13 @@ config MEDIA_TUNER_TDA18218 - help - NXP TDA18218 silicon tuner driver. - -+config MEDIA_TUNER_FC0011 -+ tristate "Fitipower FC0011 silicon tuner" -+ depends on VIDEO_MEDIA && I2C -+ default m if MEDIA_TUNER_CUSTOMISE -+ help -+ Fitipower FC0011 silicon tuner driver. -+ - config MEDIA_TUNER_TDA18212 - tristate "NXP TDA18212 silicon tuner" - depends on VIDEO_MEDIA && I2C -@@ -211,4 +218,10 @@ config MEDIA_TUNER_TDA18212 - help - NXP TDA18212 silicon tuner driver. - -+config MEDIA_TUNER_TUA9001 -+ tristate "Infineon TUA 9001 silicon tuner" -+ depends on VIDEO_MEDIA && I2C -+ default m if MEDIA_TUNER_CUSTOMISE -+ help -+ Infineon TUA 9001 silicon tuner driver. - endmenu -Index: linux-3.3.x86_64/drivers/media/common/tuners/tua9001.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/common/tuners/tua9001.c -@@ -0,0 +1,215 @@ -+/* -+ * Infineon TUA 9001 silicon tuner driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#include "tua9001.h" -+#include "tua9001_priv.h" -+ -+/* write register */ -+static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val) -+{ -+ int ret; -+ u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff }; -+ struct i2c_msg msg[1] = { -+ { -+ .addr = priv->cfg->i2c_addr, -+ .flags = 0, -+ .len = sizeof(buf), -+ .buf = buf, -+ } -+ }; -+ -+ ret = i2c_transfer(priv->i2c, msg, 1); -+ if (ret == 1) { -+ ret = 0; -+ } else { -+ printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n", -+ __func__, ret, reg); -+ ret = -EREMOTEIO; -+ } -+ -+ return ret; -+} -+ -+static int tua9001_release(struct dvb_frontend *fe) -+{ -+ kfree(fe->tuner_priv); -+ fe->tuner_priv = NULL; -+ -+ return 0; -+} -+ -+static int tua9001_init(struct dvb_frontend *fe) -+{ -+ struct tua9001_priv *priv = fe->tuner_priv; -+ int ret = 0; -+ u8 i; -+ struct reg_val data[] = { -+ { 0x1e, 0x6512 }, -+ { 0x25, 0xb888 }, -+ { 0x39, 0x5460 }, -+ { 0x3b, 0x00c0 }, -+ { 0x3a, 0xf000 }, -+ { 0x08, 0x0000 }, -+ { 0x32, 0x0030 }, -+ { 0x41, 0x703a }, -+ { 0x40, 0x1c78 }, -+ { 0x2c, 0x1c00 }, -+ { 0x36, 0xc013 }, -+ { 0x37, 0x6f18 }, -+ { 0x27, 0x0008 }, -+ { 0x2a, 0x0001 }, -+ { 0x34, 0x0a40 }, -+ }; -+ -+ if (fe->ops.i2c_gate_ctrl) -+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ -+ -+ for (i = 0; i < ARRAY_SIZE(data); i++) { -+ ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); -+ if (ret) -+ break; -+ } -+ -+ if (fe->ops.i2c_gate_ctrl) -+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ -+ -+ if (ret < 0) -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int tua9001_set_params(struct dvb_frontend *fe) -+{ -+ struct tua9001_priv *priv = fe->tuner_priv; -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ int ret, i; -+ u16 val; -+ u32 frequency; -+ struct reg_val data[2]; -+ -+ pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", -+ __func__, c->delivery_system, c->frequency, -+ c->bandwidth_hz); -+ -+ switch (c->delivery_system) { -+ case SYS_DVBT: -+ switch (c->bandwidth_hz) { -+ case 8000000: -+ val = 0x0000; -+ break; -+ case 7000000: -+ val = 0x1000; -+ break; -+ case 6000000: -+ val = 0x2000; -+ break; -+ case 5000000: -+ val = 0x3000; -+ break; -+ default: -+ ret = -EINVAL; -+ goto err; -+ } -+ break; -+ default: -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ data[0].reg = 0x04; -+ data[0].val = val; -+ -+ frequency = (c->frequency - 150000000); -+ frequency /= 100; -+ frequency *= 48; -+ frequency /= 10000; -+ -+ data[1].reg = 0x1f; -+ data[1].val = frequency; -+ -+ if (fe->ops.i2c_gate_ctrl) -+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ -+ -+ for (i = 0; i < ARRAY_SIZE(data); i++) { -+ ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); -+ if (ret < 0) -+ break; -+ } -+ -+ if (fe->ops.i2c_gate_ctrl) -+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ -+ -+err: -+ if (ret < 0) -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -+{ -+ *frequency = 0; /* Zero-IF */ -+ -+ return 0; -+} -+ -+static const struct dvb_tuner_ops tua9001_tuner_ops = { -+ .info = { -+ .name = "Infineon TUA 9001", -+ -+ .frequency_min = 170000000, -+ .frequency_max = 862000000, -+ .frequency_step = 0, -+ }, -+ -+ .release = tua9001_release, -+ -+ .init = tua9001_init, -+ .set_params = tua9001_set_params, -+ -+ .get_if_frequency = tua9001_get_if_frequency, -+}; -+ -+struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, -+ struct i2c_adapter *i2c, struct tua9001_config *cfg) -+{ -+ struct tua9001_priv *priv = NULL; -+ -+ priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL); -+ if (priv == NULL) -+ return NULL; -+ -+ priv->cfg = cfg; -+ priv->i2c = i2c; -+ -+ printk(KERN_INFO "Infineon TUA 9001 successfully attached."); -+ -+ memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, -+ sizeof(struct dvb_tuner_ops)); -+ -+ fe->tuner_priv = priv; -+ return fe; -+} -+EXPORT_SYMBOL(tua9001_attach); -+ -+MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver"); -+MODULE_AUTHOR("Antti Palosaari "); -+MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/common/tuners/tua9001.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/common/tuners/tua9001.h -@@ -0,0 +1,46 @@ -+/* -+ * Infineon TUA 9001 silicon tuner driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#ifndef TUA9001_H -+#define TUA9001_H -+ -+#include "dvb_frontend.h" -+ -+struct tua9001_config { -+ /* -+ * I2C address -+ */ -+ u8 i2c_addr; -+}; -+ -+#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \ -+ (defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE)) -+extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, -+ struct i2c_adapter *i2c, struct tua9001_config *cfg); -+#else -+static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, -+ struct i2c_adapter *i2c, struct tua9001_config *cfg) -+{ -+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -+ return NULL; -+} -+#endif -+ -+#endif -Index: linux-3.3.x86_64/drivers/media/common/tuners/tua9001_priv.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/common/tuners/tua9001_priv.h -@@ -0,0 +1,34 @@ -+/* -+ * Infineon TUA 9001 silicon tuner driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#ifndef TUA9001_PRIV_H -+#define TUA9001_PRIV_H -+ -+struct reg_val { -+ u8 reg; -+ u16 val; -+}; -+ -+struct tua9001_priv { -+ struct tua9001_config *cfg; -+ struct i2c_adapter *i2c; -+}; -+ -+#endif -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/af9033.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/af9033.c -@@ -0,0 +1,919 @@ -+/* -+ * Afatech AF9033 demodulator driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * Copyright (C) 2012 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#include "af9033_priv.h" -+ -+struct af9033_state { -+ struct i2c_adapter *i2c; -+ struct dvb_frontend fe; -+ struct af9033_config cfg; -+ -+ u32 bandwidth_hz; -+ bool ts_mode_parallel; -+ bool ts_mode_serial; -+}; -+ -+/* write multiple registers */ -+static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, -+ int len) -+{ -+ int ret; -+ u8 buf[3 + len]; -+ struct i2c_msg msg[1] = { -+ { -+ .addr = state->cfg.i2c_addr, -+ .flags = 0, -+ .len = sizeof(buf), -+ .buf = buf, -+ } -+ }; -+ -+ buf[0] = (reg >> 16) & 0xff; -+ buf[1] = (reg >> 8) & 0xff; -+ buf[2] = (reg >> 0) & 0xff; -+ memcpy(&buf[3], val, len); -+ -+ ret = i2c_transfer(state->i2c, msg, 1); -+ if (ret == 1) { -+ ret = 0; -+ } else { -+ printk(KERN_WARNING "%s: i2c wr failed=%d reg=%06x len=%d\n", -+ __func__, ret, reg, len); -+ ret = -EREMOTEIO; -+ } -+ -+ return ret; -+} -+ -+/* read multiple registers */ -+static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) -+{ -+ int ret; -+ u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff, -+ (reg >> 0) & 0xff }; -+ struct i2c_msg msg[2] = { -+ { -+ .addr = state->cfg.i2c_addr, -+ .flags = 0, -+ .len = sizeof(buf), -+ .buf = buf -+ }, { -+ .addr = state->cfg.i2c_addr, -+ .flags = I2C_M_RD, -+ .len = len, -+ .buf = val -+ } -+ }; -+ -+ ret = i2c_transfer(state->i2c, msg, 2); -+ if (ret == 2) { -+ ret = 0; -+ } else { -+ printk(KERN_WARNING "%s: i2c rd failed=%d reg=%06x len=%d\n", -+ __func__, ret, reg, len); -+ ret = -EREMOTEIO; -+ } -+ -+ return ret; -+} -+ -+ -+/* write single register */ -+static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val) -+{ -+ return af9033_wr_regs(state, reg, &val, 1); -+} -+ -+/* read single register */ -+static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val) -+{ -+ return af9033_rd_regs(state, reg, val, 1); -+} -+ -+/* write single register with mask */ -+static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, -+ u8 mask) -+{ -+ int ret; -+ u8 tmp; -+ -+ /* no need for read if whole reg is written */ -+ if (mask != 0xff) { -+ ret = af9033_rd_regs(state, reg, &tmp, 1); -+ if (ret) -+ return ret; -+ -+ val &= mask; -+ tmp &= ~mask; -+ val |= tmp; -+ } -+ -+ return af9033_wr_regs(state, reg, &val, 1); -+} -+ -+/* read single register with mask */ -+static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, -+ u8 mask) -+{ -+ int ret, i; -+ u8 tmp; -+ -+ ret = af9033_rd_regs(state, reg, &tmp, 1); -+ if (ret) -+ return ret; -+ -+ tmp &= mask; -+ -+ /* find position of the first bit */ -+ for (i = 0; i < 8; i++) { -+ if ((mask >> i) & 0x01) -+ break; -+ } -+ *val = tmp >> i; -+ -+ return 0; -+} -+ -+static u32 af9033_div(u32 a, u32 b, u32 x) -+{ -+ u32 r = 0, c = 0, i; -+ -+ pr_debug("%s: a=%d b=%d x=%d\n", __func__, a, b, x); -+ -+ if (a > b) { -+ c = a / b; -+ a = a - c * b; -+ } -+ -+ for (i = 0; i < x; i++) { -+ if (a >= b) { -+ r += 1; -+ a -= b; -+ } -+ a <<= 1; -+ r <<= 1; -+ } -+ r = (c << (u32)x) + r; -+ -+ pr_debug("%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r); -+ -+ return r; -+} -+ -+static void af9033_release(struct dvb_frontend *fe) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ -+ kfree(state); -+} -+ -+static int af9033_init(struct dvb_frontend *fe) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ int ret, i, len; -+ const struct reg_val *init; -+ u8 buf[4]; -+ u32 adc_cw, clock_cw; -+ struct reg_val_mask tab[] = { -+ { 0x80fb24, 0x00, 0x08 }, -+ { 0x80004c, 0x00, 0xff }, -+ { 0x00f641, state->cfg.tuner, 0xff }, -+ { 0x80f5ca, 0x01, 0x01 }, -+ { 0x80f715, 0x01, 0x01 }, -+ { 0x00f41f, 0x04, 0x04 }, -+ { 0x00f41a, 0x01, 0x01 }, -+ { 0x80f731, 0x00, 0x01 }, -+ { 0x00d91e, 0x00, 0x01 }, -+ { 0x00d919, 0x00, 0x01 }, -+ { 0x80f732, 0x00, 0x01 }, -+ { 0x00d91f, 0x00, 0x01 }, -+ { 0x00d91a, 0x00, 0x01 }, -+ { 0x80f730, 0x00, 0x01 }, -+ { 0x80f778, 0x00, 0xff }, -+ { 0x80f73c, 0x01, 0x01 }, -+ { 0x80f776, 0x00, 0x01 }, -+ { 0x00d8fd, 0x01, 0xff }, -+ { 0x00d830, 0x01, 0xff }, -+ { 0x00d831, 0x00, 0xff }, -+ { 0x00d832, 0x00, 0xff }, -+ { 0x80f985, state->ts_mode_serial, 0x01 }, -+ { 0x80f986, state->ts_mode_parallel, 0x01 }, -+ { 0x00d827, 0x00, 0xff }, -+ { 0x00d829, 0x00, 0xff }, -+ }; -+ -+ /* program clock control */ -+ clock_cw = af9033_div(state->cfg.clock, 1000000ul, 19ul); -+ buf[0] = (clock_cw >> 0) & 0xff; -+ buf[1] = (clock_cw >> 8) & 0xff; -+ buf[2] = (clock_cw >> 16) & 0xff; -+ buf[3] = (clock_cw >> 24) & 0xff; -+ -+ pr_debug("%s: clock=%d clock_cw=%08x\n", __func__, state->cfg.clock, -+ clock_cw); -+ -+ ret = af9033_wr_regs(state, 0x800025, buf, 4); -+ if (ret < 0) -+ goto err; -+ -+ /* program ADC control */ -+ for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { -+ if (clock_adc_lut[i].clock == state->cfg.clock) -+ break; -+ } -+ -+ adc_cw = af9033_div(clock_adc_lut[i].adc, 1000000ul, 19ul); -+ buf[0] = (adc_cw >> 0) & 0xff; -+ buf[1] = (adc_cw >> 8) & 0xff; -+ buf[2] = (adc_cw >> 16) & 0xff; -+ -+ pr_debug("%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc, -+ adc_cw); -+ -+ ret = af9033_wr_regs(state, 0x80f1cd, buf, 3); -+ if (ret < 0) -+ goto err; -+ -+ /* program register table */ -+ for (i = 0; i < ARRAY_SIZE(tab); i++) { -+ ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val, -+ tab[i].mask); -+ if (ret < 0) -+ goto err; -+ } -+ -+ /* settings for TS interface */ -+ if (state->cfg.ts_mode == AF9033_TS_MODE_USB) { -+ ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01); -+ if (ret < 0) -+ goto err; -+ } else { -+ ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01); -+ if (ret < 0) -+ goto err; -+ } -+ -+ /* load OFSM settings */ -+ pr_debug("%s: load ofsm settings\n", __func__); -+ len = ARRAY_SIZE(ofsm_init); -+ init = ofsm_init; -+ for (i = 0; i < len; i++) { -+ ret = af9033_wr_reg(state, init[i].reg, init[i].val); -+ if (ret < 0) -+ goto err; -+ } -+ -+ /* load tuner specific settings */ -+ pr_debug("%s: load tuner specific settings\n", -+ __func__); -+ switch (state->cfg.tuner) { -+ case AF9033_TUNER_TUA9001: -+ len = ARRAY_SIZE(tuner_init_tua9001); -+ init = tuner_init_tua9001; -+ break; -+ case AF9033_TUNER_FC0011: -+ len = ARRAY_SIZE(tuner_init_fc0011); -+ init = tuner_init_fc0011; -+ break; -+ case AF9033_TUNER_MXL5007T: -+ len = ARRAY_SIZE(tuner_init_mxl5007t); -+ init = tuner_init_mxl5007t; -+ break; -+ case AF9033_TUNER_TDA18218: -+ len = ARRAY_SIZE(tuner_init_tda18218); -+ init = tuner_init_tda18218; -+ break; -+ default: -+ pr_debug("%s: unsupported tuner ID=%d\n", __func__, -+ state->cfg.tuner); -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ for (i = 0; i < len; i++) { -+ ret = af9033_wr_reg(state, init[i].reg, init[i].val); -+ if (ret < 0) -+ goto err; -+ } -+ -+ state->bandwidth_hz = 0; /* force to program all parameters */ -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9033_sleep(struct dvb_frontend *fe) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ int ret, i; -+ u8 tmp; -+ -+ ret = af9033_wr_reg(state, 0x80004c, 1); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_wr_reg(state, 0x800000, 0); -+ if (ret < 0) -+ goto err; -+ -+ for (i = 100, tmp = 1; i && tmp; i--) { -+ ret = af9033_rd_reg(state, 0x80004c, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ usleep_range(200, 10000); -+ } -+ -+ pr_debug("%s: loop=%d\n", __func__, i); -+ -+ if (i == 0) { -+ ret = -ETIMEDOUT; -+ goto err; -+ } -+ -+ ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08); -+ if (ret < 0) -+ goto err; -+ -+ /* prevent current leak (?) */ -+ if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { -+ /* enable parallel TS */ -+ ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01); -+ if (ret < 0) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9033_get_tune_settings(struct dvb_frontend *fe, -+ struct dvb_frontend_tune_settings *fesettings) -+{ -+ fesettings->min_delay_ms = 800; -+ fesettings->step_size = 0; -+ fesettings->max_drift = 0; -+ -+ return 0; -+} -+ -+static int af9033_set_frontend(struct dvb_frontend *fe) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ int ret, i, spec_inv; -+ u8 tmp, buf[3], bandwidth_reg_val; -+ u32 if_frequency, freq_cw, adc_freq; -+ -+ pr_debug("%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency, -+ c->bandwidth_hz); -+ -+ /* check bandwidth */ -+ switch (c->bandwidth_hz) { -+ case 6000000: -+ bandwidth_reg_val = 0x00; -+ break; -+ case 7000000: -+ bandwidth_reg_val = 0x01; -+ break; -+ case 8000000: -+ bandwidth_reg_val = 0x02; -+ break; -+ default: -+ pr_debug("%s: invalid bandwidth_hz\n", __func__); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ /* program tuner */ -+ if (fe->ops.tuner_ops.set_params) -+ fe->ops.tuner_ops.set_params(fe); -+ -+ /* program CFOE coefficients */ -+ if (c->bandwidth_hz != state->bandwidth_hz) { -+ for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { -+ if (coeff_lut[i].clock == state->cfg.clock && -+ coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { -+ break; -+ } -+ } -+ ret = af9033_wr_regs(state, 0x800001, -+ coeff_lut[i].val, sizeof(coeff_lut[i].val)); -+ } -+ -+ /* program frequency control */ -+ if (c->bandwidth_hz != state->bandwidth_hz) { -+ spec_inv = state->cfg.spec_inv ? -1 : 1; -+ -+ for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { -+ if (clock_adc_lut[i].clock == state->cfg.clock) -+ break; -+ } -+ adc_freq = clock_adc_lut[i].adc; -+ -+ /* get used IF frequency */ -+ if (fe->ops.tuner_ops.get_if_frequency) -+ fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); -+ else -+ if_frequency = 0; -+ -+ while (if_frequency > (adc_freq / 2)) -+ if_frequency -= adc_freq; -+ -+ if (if_frequency >= 0) -+ spec_inv *= -1; -+ else -+ if_frequency *= -1; -+ -+ freq_cw = af9033_div(if_frequency, adc_freq, 23ul); -+ -+ if (spec_inv == -1) -+ freq_cw *= -1; -+ -+ /* get adc multiplies */ -+ ret = af9033_rd_reg(state, 0x800045, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ if (tmp == 1) -+ freq_cw /= 2; -+ -+ buf[0] = (freq_cw >> 0) & 0xff; -+ buf[1] = (freq_cw >> 8) & 0xff; -+ buf[2] = (freq_cw >> 16) & 0x7f; -+ ret = af9033_wr_regs(state, 0x800029, buf, 3); -+ if (ret < 0) -+ goto err; -+ -+ state->bandwidth_hz = c->bandwidth_hz; -+ } -+ -+ ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_wr_reg(state, 0x800040, 0x00); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_wr_reg(state, 0x800047, 0x00); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ if (c->frequency <= 230000000) -+ tmp = 0x00; /* VHF */ -+ else -+ tmp = 0x01; /* UHF */ -+ -+ ret = af9033_wr_reg(state, 0x80004b, tmp); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_wr_reg(state, 0x800000, 0x00); -+ if (ret < 0) -+ goto err; -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9033_get_frontend(struct dvb_frontend *fe) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -+ int ret; -+ u8 buf[8]; -+ -+ pr_debug("%s\n", __func__); -+ -+ /* read all needed registers */ -+ ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf)); -+ if (ret < 0) -+ goto err; -+ -+ switch ((buf[0] >> 0) & 3) { -+ case 0: -+ c->transmission_mode = TRANSMISSION_MODE_2K; -+ break; -+ case 1: -+ c->transmission_mode = TRANSMISSION_MODE_8K; -+ break; -+ } -+ -+ switch ((buf[1] >> 0) & 3) { -+ case 0: -+ c->guard_interval = GUARD_INTERVAL_1_32; -+ break; -+ case 1: -+ c->guard_interval = GUARD_INTERVAL_1_16; -+ break; -+ case 2: -+ c->guard_interval = GUARD_INTERVAL_1_8; -+ break; -+ case 3: -+ c->guard_interval = GUARD_INTERVAL_1_4; -+ break; -+ } -+ -+ switch ((buf[2] >> 0) & 7) { -+ case 0: -+ c->hierarchy = HIERARCHY_NONE; -+ break; -+ case 1: -+ c->hierarchy = HIERARCHY_1; -+ break; -+ case 2: -+ c->hierarchy = HIERARCHY_2; -+ break; -+ case 3: -+ c->hierarchy = HIERARCHY_4; -+ break; -+ } -+ -+ switch ((buf[3] >> 0) & 3) { -+ case 0: -+ c->modulation = QPSK; -+ break; -+ case 1: -+ c->modulation = QAM_16; -+ break; -+ case 2: -+ c->modulation = QAM_64; -+ break; -+ } -+ -+ switch ((buf[4] >> 0) & 3) { -+ case 0: -+ c->bandwidth_hz = 6000000; -+ break; -+ case 1: -+ c->bandwidth_hz = 7000000; -+ break; -+ case 2: -+ c->bandwidth_hz = 8000000; -+ break; -+ } -+ -+ switch ((buf[6] >> 0) & 7) { -+ case 0: -+ c->code_rate_HP = FEC_1_2; -+ break; -+ case 1: -+ c->code_rate_HP = FEC_2_3; -+ break; -+ case 2: -+ c->code_rate_HP = FEC_3_4; -+ break; -+ case 3: -+ c->code_rate_HP = FEC_5_6; -+ break; -+ case 4: -+ c->code_rate_HP = FEC_7_8; -+ break; -+ case 5: -+ c->code_rate_HP = FEC_NONE; -+ break; -+ } -+ -+ switch ((buf[7] >> 0) & 7) { -+ case 0: -+ c->code_rate_LP = FEC_1_2; -+ break; -+ case 1: -+ c->code_rate_LP = FEC_2_3; -+ break; -+ case 2: -+ c->code_rate_LP = FEC_3_4; -+ break; -+ case 3: -+ c->code_rate_LP = FEC_5_6; -+ break; -+ case 4: -+ c->code_rate_LP = FEC_7_8; -+ break; -+ case 5: -+ c->code_rate_LP = FEC_NONE; -+ break; -+ } -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ int ret; -+ u8 tmp; -+ -+ *status = 0; -+ -+ /* radio channel status, 0=no result, 1=has signal, 2=no signal */ -+ ret = af9033_rd_reg(state, 0x800047, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ /* has signal */ -+ if (tmp == 0x01) -+ *status |= FE_HAS_SIGNAL; -+ -+ if (tmp != 0x02) { -+ /* TPS lock */ -+ ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ if (tmp) -+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | -+ FE_HAS_VITERBI; -+ -+ /* full lock */ -+ ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ if (tmp) -+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | -+ FE_HAS_VITERBI | FE_HAS_SYNC | -+ FE_HAS_LOCK; -+ } -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ int ret, i, len; -+ u8 buf[3], tmp; -+ u32 snr_val; -+ const struct val_snr *uninitialized_var(snr_lut); -+ -+ /* read value */ -+ ret = af9033_rd_regs(state, 0x80002c, buf, 3); -+ if (ret < 0) -+ goto err; -+ -+ snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; -+ -+ /* read current modulation */ -+ ret = af9033_rd_reg(state, 0x80f903, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ switch ((tmp >> 0) & 3) { -+ case 0: -+ len = ARRAY_SIZE(qpsk_snr_lut); -+ snr_lut = qpsk_snr_lut; -+ break; -+ case 1: -+ len = ARRAY_SIZE(qam16_snr_lut); -+ snr_lut = qam16_snr_lut; -+ break; -+ case 2: -+ len = ARRAY_SIZE(qam64_snr_lut); -+ snr_lut = qam64_snr_lut; -+ break; -+ default: -+ goto err; -+ } -+ -+ for (i = 0; i < len; i++) { -+ tmp = snr_lut[i].snr; -+ -+ if (snr_val < snr_lut[i].val) -+ break; -+ } -+ -+ *snr = tmp * 10; /* dB/10 */ -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ int ret; -+ u8 strength2; -+ -+ /* read signal strength of 0-100 scale */ -+ ret = af9033_rd_reg(state, 0x800048, &strength2); -+ if (ret < 0) -+ goto err; -+ -+ /* scale value to 0x0000-0xffff */ -+ *strength = strength2 * 0xffff / 100; -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) -+{ -+ *ber = 0; -+ -+ return 0; -+} -+ -+static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -+{ -+ *ucblocks = 0; -+ -+ return 0; -+} -+ -+static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -+{ -+ struct af9033_state *state = fe->demodulator_priv; -+ int ret; -+ -+ pr_debug("%s: enable=%d\n", __func__, enable); -+ -+ ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static struct dvb_frontend_ops af9033_ops; -+ -+struct dvb_frontend *af9033_attach(const struct af9033_config *config, -+ struct i2c_adapter *i2c) -+{ -+ int ret; -+ struct af9033_state *state; -+ u8 buf[8]; -+ -+ pr_debug("%s:\n", __func__); -+ -+ /* allocate memory for the internal state */ -+ state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL); -+ if (state == NULL) -+ goto err; -+ -+ /* setup the state */ -+ state->i2c = i2c; -+ memcpy(&state->cfg, config, sizeof(struct af9033_config)); -+ -+ if (state->cfg.clock != 12000000) { -+ printk(KERN_INFO "af9033: unsupported clock=%d, only " \ -+ "12000000 Hz is supported currently\n", -+ state->cfg.clock); -+ goto err; -+ } -+ -+ /* firmware version */ -+ ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9033_rd_regs(state, 0x804191, &buf[4], 4); -+ if (ret < 0) -+ goto err; -+ -+ printk(KERN_INFO "af9033: firmware version: LINK=%d.%d.%d.%d " \ -+ "OFDM=%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3], -+ buf[4], buf[5], buf[6], buf[7]); -+ -+ /* configure internal TS mode */ -+ switch (state->cfg.ts_mode) { -+ case AF9033_TS_MODE_PARALLEL: -+ state->ts_mode_parallel = true; -+ break; -+ case AF9033_TS_MODE_SERIAL: -+ state->ts_mode_serial = true; -+ break; -+ case AF9033_TS_MODE_USB: -+ /* usb mode for AF9035 */ -+ default: -+ break; -+ } -+ -+ /* create dvb_frontend */ -+ memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); -+ state->fe.demodulator_priv = state; -+ -+ return &state->fe; -+ -+err: -+ kfree(state); -+ return NULL; -+} -+EXPORT_SYMBOL(af9033_attach); -+ -+static struct dvb_frontend_ops af9033_ops = { -+ .delsys = { SYS_DVBT }, -+ .info = { -+ .name = "Afatech AF9033 (DVB-T)", -+ .frequency_min = 174000000, -+ .frequency_max = 862000000, -+ .frequency_stepsize = 250000, -+ .frequency_tolerance = 0, -+ .caps = FE_CAN_FEC_1_2 | -+ FE_CAN_FEC_2_3 | -+ FE_CAN_FEC_3_4 | -+ FE_CAN_FEC_5_6 | -+ FE_CAN_FEC_7_8 | -+ FE_CAN_FEC_AUTO | -+ FE_CAN_QPSK | -+ FE_CAN_QAM_16 | -+ FE_CAN_QAM_64 | -+ FE_CAN_QAM_AUTO | -+ FE_CAN_TRANSMISSION_MODE_AUTO | -+ FE_CAN_GUARD_INTERVAL_AUTO | -+ FE_CAN_HIERARCHY_AUTO | -+ FE_CAN_RECOVER | -+ FE_CAN_MUTE_TS -+ }, -+ -+ .release = af9033_release, -+ -+ .init = af9033_init, -+ .sleep = af9033_sleep, -+ -+ .get_tune_settings = af9033_get_tune_settings, -+ .set_frontend = af9033_set_frontend, -+ .get_frontend = af9033_get_frontend, -+ -+ .read_status = af9033_read_status, -+ .read_snr = af9033_read_snr, -+ .read_signal_strength = af9033_read_signal_strength, -+ .read_ber = af9033_read_ber, -+ .read_ucblocks = af9033_read_ucblocks, -+ -+ .i2c_gate_ctrl = af9033_i2c_gate_ctrl, -+}; -+ -+MODULE_AUTHOR("Antti Palosaari "); -+MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver"); -+MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/af9033.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/af9033.h -@@ -0,0 +1,75 @@ -+/* -+ * Afatech AF9033 demodulator driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * Copyright (C) 2012 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#ifndef AF9033_H -+#define AF9033_H -+ -+struct af9033_config { -+ /* -+ * I2C address -+ */ -+ u8 i2c_addr; -+ -+ /* -+ * clock Hz -+ * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000, -+ * 30000000, 36000000, 20480000, 16384000 -+ */ -+ u32 clock; -+ -+ /* -+ * tuner -+ */ -+#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */ -+#define AF9033_TUNER_FC0011 0x28 /* Fitipower FC0011 */ -+#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */ -+#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */ -+ u8 tuner; -+ -+ /* -+ * TS settings -+ */ -+#define AF9033_TS_MODE_USB 0 -+#define AF9033_TS_MODE_PARALLEL 1 -+#define AF9033_TS_MODE_SERIAL 2 -+ u8 ts_mode:2; -+ -+ /* -+ * input spectrum inversion -+ */ -+ bool spec_inv; -+}; -+ -+ -+#if defined(CONFIG_DVB_AF9033) || \ -+ (defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE)) -+extern struct dvb_frontend *af9033_attach(const struct af9033_config *config, -+ struct i2c_adapter *i2c); -+#else -+static inline struct dvb_frontend *af9033_attach( -+ const struct af9033_config *config, struct i2c_adapter *i2c) -+{ -+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -+ return NULL; -+} -+#endif -+ -+#endif /* AF9033_H */ -Index: linux-3.3.x86_64/drivers/media/dvb/frontends/af9033_priv.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/frontends/af9033_priv.h -@@ -0,0 +1,470 @@ -+/* -+ * Afatech AF9033 demodulator driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * Copyright (C) 2012 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#ifndef AF9033_PRIV_H -+#define AF9033_PRIV_H -+ -+#include "dvb_frontend.h" -+#include "af9033.h" -+ -+struct reg_val { -+ u32 reg; -+ u8 val; -+}; -+ -+struct reg_val_mask { -+ u32 reg; -+ u8 val; -+ u8 mask; -+}; -+ -+struct coeff { -+ u32 clock; -+ u32 bandwidth_hz; -+ u8 val[36]; -+}; -+ -+struct clock_adc { -+ u32 clock; -+ u32 adc; -+}; -+ -+struct val_snr { -+ u32 val; -+ u8 snr; -+}; -+ -+/* Xtal clock vs. ADC clock lookup table */ -+static const struct clock_adc clock_adc_lut[] = { -+ { 16384000, 20480000 }, -+ { 20480000, 20480000 }, -+ { 36000000, 20250000 }, -+ { 30000000, 20156250 }, -+ { 26000000, 20583333 }, -+ { 28000000, 20416667 }, -+ { 32000000, 20500000 }, -+ { 34000000, 20187500 }, -+ { 24000000, 20500000 }, -+ { 22000000, 20625000 }, -+ { 12000000, 20250000 }, -+}; -+ -+/* pre-calculated coeff lookup table */ -+static const struct coeff coeff_lut[] = { -+ /* 12.000 MHz */ -+ { 12000000, 8000000, { -+ 0x01, 0xce, 0x55, 0xc9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73, -+ 0x99, 0x0f, 0x00, 0x73, 0x95, 0x72, 0x00, 0x73, 0x91, 0xd5, -+ 0x00, 0x39, 0xca, 0xb9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73, -+ 0x95, 0x72, 0x37, 0x02, 0xce, 0x01 } -+ }, -+ { 12000000, 7000000, { -+ 0x01, 0x94, 0x8b, 0x10, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65, -+ 0x25, 0xed, 0x00, 0x65, 0x22, 0xc4, 0x00, 0x65, 0x1f, 0x9b, -+ 0x00, 0x32, 0x91, 0x62, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65, -+ 0x22, 0xc4, 0x88, 0x02, 0x95, 0x01 } -+ }, -+ { 12000000, 6000000, { -+ 0x01, 0x5a, 0xc0, 0x56, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56, -+ 0xb2, 0xcb, 0x00, 0x56, 0xb0, 0x15, 0x00, 0x56, 0xad, 0x60, -+ 0x00, 0x2b, 0x58, 0x0b, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56, -+ 0xb0, 0x15, 0xf4, 0x02, 0x5b, 0x01 } -+ }, -+}; -+ -+/* QPSK SNR lookup table */ -+static const struct val_snr qpsk_snr_lut[] = { -+ { 0x0b4771, 0 }, -+ { 0x0c1aed, 1 }, -+ { 0x0d0d27, 2 }, -+ { 0x0e4d19, 3 }, -+ { 0x0e5da8, 4 }, -+ { 0x107097, 5 }, -+ { 0x116975, 6 }, -+ { 0x1252d9, 7 }, -+ { 0x131fa4, 8 }, -+ { 0x13d5e1, 9 }, -+ { 0x148e53, 10 }, -+ { 0x15358b, 11 }, -+ { 0x15dd29, 12 }, -+ { 0x168112, 13 }, -+ { 0x170b61, 14 }, -+ { 0x17a532, 15 }, -+ { 0x180f94, 16 }, -+ { 0x186ed2, 17 }, -+ { 0x18b271, 18 }, -+ { 0x18e118, 19 }, -+ { 0x18ff4b, 20 }, -+ { 0x190af1, 21 }, -+ { 0x191451, 22 }, -+ { 0xffffff, 23 }, -+}; -+ -+/* QAM16 SNR lookup table */ -+static const struct val_snr qam16_snr_lut[] = { -+ { 0x04f0d5, 0 }, -+ { 0x05387a, 1 }, -+ { 0x0573a4, 2 }, -+ { 0x05a99e, 3 }, -+ { 0x05cc80, 4 }, -+ { 0x05eb62, 5 }, -+ { 0x05fecf, 6 }, -+ { 0x060b80, 7 }, -+ { 0x062501, 8 }, -+ { 0x064865, 9 }, -+ { 0x069604, 10 }, -+ { 0x06f356, 11 }, -+ { 0x07706a, 12 }, -+ { 0x0804d3, 13 }, -+ { 0x089d1a, 14 }, -+ { 0x093e3d, 15 }, -+ { 0x09e35d, 16 }, -+ { 0x0a7c3c, 17 }, -+ { 0x0afaf8, 18 }, -+ { 0x0b719d, 19 }, -+ { 0x0bda6a, 20 }, -+ { 0x0c0c75, 21 }, -+ { 0x0c3f7d, 22 }, -+ { 0x0c5e62, 23 }, -+ { 0x0c6c31, 24 }, -+ { 0x0c7925, 25 }, -+ { 0xffffff, 26 }, -+}; -+ -+/* QAM64 SNR lookup table */ -+static const struct val_snr qam64_snr_lut[] = { -+ { 0x0256d0, 0 }, -+ { 0x027a65, 1 }, -+ { 0x029873, 2 }, -+ { 0x02b7fe, 3 }, -+ { 0x02cf1e, 4 }, -+ { 0x02e234, 5 }, -+ { 0x02f409, 6 }, -+ { 0x030046, 7 }, -+ { 0x030844, 8 }, -+ { 0x030a02, 9 }, -+ { 0x030cde, 10 }, -+ { 0x031031, 11 }, -+ { 0x03144c, 12 }, -+ { 0x0315dd, 13 }, -+ { 0x031920, 14 }, -+ { 0x0322d0, 15 }, -+ { 0x0339fc, 16 }, -+ { 0x0364a1, 17 }, -+ { 0x038bcc, 18 }, -+ { 0x03c7d3, 19 }, -+ { 0x0408cc, 20 }, -+ { 0x043bed, 21 }, -+ { 0x048061, 22 }, -+ { 0x04be95, 23 }, -+ { 0x04fa7d, 24 }, -+ { 0x052405, 25 }, -+ { 0x05570d, 26 }, -+ { 0x059feb, 27 }, -+ { 0x05bf38, 28 }, -+ { 0xffffff, 29 }, -+}; -+ -+static const struct reg_val ofsm_init[] = { -+ { 0x800051, 0x01 }, -+ { 0x800070, 0x0a }, -+ { 0x80007e, 0x04 }, -+ { 0x800081, 0x0a }, -+ { 0x80008a, 0x01 }, -+ { 0x80008e, 0x01 }, -+ { 0x800092, 0x06 }, -+ { 0x800099, 0x01 }, -+ { 0x80009f, 0xe1 }, -+ { 0x8000a0, 0xcf }, -+ { 0x8000a3, 0x01 }, -+ { 0x8000a5, 0x01 }, -+ { 0x8000a6, 0x01 }, -+ { 0x8000a9, 0x00 }, -+ { 0x8000aa, 0x01 }, -+ { 0x8000ab, 0x01 }, -+ { 0x8000b0, 0x01 }, -+ { 0x8000c0, 0x05 }, -+ { 0x8000c4, 0x19 }, -+ { 0x80f000, 0x0f }, -+ { 0x80f016, 0x10 }, -+ { 0x80f017, 0x04 }, -+ { 0x80f018, 0x05 }, -+ { 0x80f019, 0x04 }, -+ { 0x80f01a, 0x05 }, -+ { 0x80f021, 0x03 }, -+ { 0x80f022, 0x0a }, -+ { 0x80f023, 0x0a }, -+ { 0x80f02b, 0x00 }, -+ { 0x80f02c, 0x01 }, -+ { 0x80f064, 0x03 }, -+ { 0x80f065, 0xf9 }, -+ { 0x80f066, 0x03 }, -+ { 0x80f067, 0x01 }, -+ { 0x80f06f, 0xe0 }, -+ { 0x80f070, 0x03 }, -+ { 0x80f072, 0x0f }, -+ { 0x80f073, 0x03 }, -+ { 0x80f078, 0x00 }, -+ { 0x80f087, 0x00 }, -+ { 0x80f09b, 0x3f }, -+ { 0x80f09c, 0x00 }, -+ { 0x80f09d, 0x20 }, -+ { 0x80f09e, 0x00 }, -+ { 0x80f09f, 0x0c }, -+ { 0x80f0a0, 0x00 }, -+ { 0x80f130, 0x04 }, -+ { 0x80f132, 0x04 }, -+ { 0x80f144, 0x1a }, -+ { 0x80f146, 0x00 }, -+ { 0x80f14a, 0x01 }, -+ { 0x80f14c, 0x00 }, -+ { 0x80f14d, 0x00 }, -+ { 0x80f14f, 0x04 }, -+ { 0x80f158, 0x7f }, -+ { 0x80f15a, 0x00 }, -+ { 0x80f15b, 0x08 }, -+ { 0x80f15d, 0x03 }, -+ { 0x80f15e, 0x05 }, -+ { 0x80f163, 0x05 }, -+ { 0x80f166, 0x01 }, -+ { 0x80f167, 0x40 }, -+ { 0x80f168, 0x0f }, -+ { 0x80f17a, 0x00 }, -+ { 0x80f17b, 0x00 }, -+ { 0x80f183, 0x01 }, -+ { 0x80f19d, 0x40 }, -+ { 0x80f1bc, 0x36 }, -+ { 0x80f1bd, 0x00 }, -+ { 0x80f1cb, 0xa0 }, -+ { 0x80f1cc, 0x01 }, -+ { 0x80f204, 0x10 }, -+ { 0x80f214, 0x00 }, -+ { 0x80f40e, 0x0a }, -+ { 0x80f40f, 0x40 }, -+ { 0x80f410, 0x08 }, -+ { 0x80f55f, 0x0a }, -+ { 0x80f561, 0x15 }, -+ { 0x80f562, 0x20 }, -+ { 0x80f5df, 0xfb }, -+ { 0x80f5e0, 0x00 }, -+ { 0x80f5e3, 0x09 }, -+ { 0x80f5e4, 0x01 }, -+ { 0x80f5e5, 0x01 }, -+ { 0x80f5f8, 0x01 }, -+ { 0x80f5fd, 0x01 }, -+ { 0x80f600, 0x05 }, -+ { 0x80f601, 0x08 }, -+ { 0x80f602, 0x0b }, -+ { 0x80f603, 0x0e }, -+ { 0x80f604, 0x11 }, -+ { 0x80f605, 0x14 }, -+ { 0x80f606, 0x17 }, -+ { 0x80f607, 0x1f }, -+ { 0x80f60e, 0x00 }, -+ { 0x80f60f, 0x04 }, -+ { 0x80f610, 0x32 }, -+ { 0x80f611, 0x10 }, -+ { 0x80f707, 0xfc }, -+ { 0x80f708, 0x00 }, -+ { 0x80f709, 0x37 }, -+ { 0x80f70a, 0x00 }, -+ { 0x80f78b, 0x01 }, -+ { 0x80f80f, 0x40 }, -+ { 0x80f810, 0x54 }, -+ { 0x80f811, 0x5a }, -+ { 0x80f905, 0x01 }, -+ { 0x80fb06, 0x03 }, -+ { 0x80fd8b, 0x00 }, -+}; -+ -+/* Infineon TUA 9001 tuner init -+ AF9033_TUNER_TUA9001 = 0x27 */ -+static const struct reg_val tuner_init_tua9001[] = { -+ { 0x800046, 0x27 }, -+ { 0x800057, 0x00 }, -+ { 0x800058, 0x01 }, -+ { 0x80005f, 0x00 }, -+ { 0x800060, 0x00 }, -+ { 0x80006d, 0x00 }, -+ { 0x800071, 0x05 }, -+ { 0x800072, 0x02 }, -+ { 0x800074, 0x01 }, -+ { 0x800075, 0x03 }, -+ { 0x800076, 0x02 }, -+ { 0x800077, 0x00 }, -+ { 0x800078, 0x01 }, -+ { 0x800079, 0x00 }, -+ { 0x80007a, 0x7e }, -+ { 0x80007b, 0x3e }, -+ { 0x800093, 0x00 }, -+ { 0x800094, 0x01 }, -+ { 0x800095, 0x02 }, -+ { 0x800096, 0x01 }, -+ { 0x800098, 0x0a }, -+ { 0x80009b, 0x05 }, -+ { 0x80009c, 0x80 }, -+ { 0x8000b3, 0x00 }, -+ { 0x8000c1, 0x01 }, -+ { 0x8000c2, 0x00 }, -+ { 0x80f007, 0x00 }, -+ { 0x80f01f, 0x82 }, -+ { 0x80f020, 0x00 }, -+ { 0x80f029, 0x82 }, -+ { 0x80f02a, 0x00 }, -+ { 0x80f047, 0x00 }, -+ { 0x80f054, 0x00 }, -+ { 0x80f055, 0x00 }, -+ { 0x80f077, 0x01 }, -+ { 0x80f1e6, 0x00 }, -+}; -+ -+/* Fitipower fc0011 tuner init -+ AF9033_TUNER_FC0011 = 0x28 */ -+static const struct reg_val tuner_init_fc0011[] = { -+ { 0x800046, AF9033_TUNER_FC0011 }, -+ { 0x800057, 0x00 }, -+ { 0x800058, 0x01 }, -+ { 0x80005f, 0x00 }, -+ { 0x800060, 0x00 }, -+ { 0x800068, 0xa5 }, -+ { 0x80006e, 0x01 }, -+ { 0x800071, 0x0A }, -+ { 0x800072, 0x02 }, -+ { 0x800074, 0x01 }, -+ { 0x800079, 0x01 }, -+ { 0x800093, 0x00 }, -+ { 0x800094, 0x00 }, -+ { 0x800095, 0x00 }, -+ { 0x800096, 0x00 }, -+ { 0x80009b, 0x2D }, -+ { 0x80009c, 0x60 }, -+ { 0x80009d, 0x23 }, -+ { 0x8000a4, 0x50 }, -+ { 0x8000ad, 0x50 }, -+ { 0x8000b3, 0x01 }, -+ { 0x8000b7, 0x88 }, -+ { 0x8000b8, 0xa6 }, -+ { 0x8000c3, 0x01 }, -+ { 0x8000c4, 0x01 }, -+ { 0x8000c7, 0x69 }, -+ { 0x80F007, 0x00 }, -+ { 0x80F00A, 0x1B }, -+ { 0x80F00B, 0x1B }, -+ { 0x80F00C, 0x1B }, -+ { 0x80F00D, 0x1B }, -+ { 0x80F00E, 0xFF }, -+ { 0x80F00F, 0x01 }, -+ { 0x80F010, 0x00 }, -+ { 0x80F011, 0x02 }, -+ { 0x80F012, 0xFF }, -+ { 0x80F013, 0x01 }, -+ { 0x80F014, 0x00 }, -+ { 0x80F015, 0x02 }, -+ { 0x80F01B, 0xEF }, -+ { 0x80F01C, 0x01 }, -+ { 0x80F01D, 0x0f }, -+ { 0x80F01E, 0x02 }, -+ { 0x80F01F, 0x6E }, -+ { 0x80F020, 0x00 }, -+ { 0x80F025, 0xDE }, -+ { 0x80F026, 0x00 }, -+ { 0x80F027, 0x0A }, -+ { 0x80F028, 0x03 }, -+ { 0x80F029, 0x6E }, -+ { 0x80F02A, 0x00 }, -+ { 0x80F047, 0x00 }, -+ { 0x80F054, 0x00 }, -+ { 0x80F055, 0x00 }, -+ { 0x80F077, 0x01 }, -+ { 0x80F1E6, 0x00 }, -+}; -+ -+/* MaxLinear MxL5007T tuner init -+ AF9033_TUNER_MXL5007T = 0xa0 */ -+static const struct reg_val tuner_init_mxl5007t[] = { -+ { 0x800046, 0x1b }, -+ { 0x800057, 0x01 }, -+ { 0x800058, 0x01 }, -+ { 0x80005f, 0x00 }, -+ { 0x800060, 0x00 }, -+ { 0x800068, 0x96 }, -+ { 0x800071, 0x05 }, -+ { 0x800072, 0x02 }, -+ { 0x800074, 0x01 }, -+ { 0x800079, 0x01 }, -+ { 0x800093, 0x00 }, -+ { 0x800094, 0x00 }, -+ { 0x800095, 0x00 }, -+ { 0x800096, 0x00 }, -+ { 0x8000b3, 0x01 }, -+ { 0x8000c1, 0x01 }, -+ { 0x8000c2, 0x00 }, -+ { 0x80f007, 0x00 }, -+ { 0x80f00c, 0x19 }, -+ { 0x80f00d, 0x1a }, -+ { 0x80f012, 0xda }, -+ { 0x80f013, 0x00 }, -+ { 0x80f014, 0x00 }, -+ { 0x80f015, 0x02 }, -+ { 0x80f01f, 0x82 }, -+ { 0x80f020, 0x00 }, -+ { 0x80f029, 0x82 }, -+ { 0x80f02a, 0x00 }, -+ { 0x80f077, 0x02 }, -+ { 0x80f1e6, 0x00 }, -+}; -+ -+/* NXP TDA 18218HN tuner init -+ AF9033_TUNER_TDA18218 = 0xa1 */ -+static const struct reg_val tuner_init_tda18218[] = { -+ {0x800046, 0xa1}, -+ {0x800057, 0x01}, -+ {0x800058, 0x01}, -+ {0x80005f, 0x00}, -+ {0x800060, 0x00}, -+ {0x800071, 0x05}, -+ {0x800072, 0x02}, -+ {0x800074, 0x01}, -+ {0x800079, 0x01}, -+ {0x800093, 0x00}, -+ {0x800094, 0x00}, -+ {0x800095, 0x00}, -+ {0x800096, 0x00}, -+ {0x8000b3, 0x01}, -+ {0x8000c3, 0x01}, -+ {0x8000c4, 0x00}, -+ {0x80f007, 0x00}, -+ {0x80f00c, 0x19}, -+ {0x80f00d, 0x1a}, -+ {0x80f012, 0xda}, -+ {0x80f013, 0x00}, -+ {0x80f014, 0x00}, -+ {0x80f015, 0x02}, -+ {0x80f01f, 0x82}, -+ {0x80f020, 0x00}, -+ {0x80f029, 0x82}, -+ {0x80f02a, 0x00}, -+ {0x80f077, 0x02}, -+ {0x80f1e6, 0x00}, -+}; -+ -+#endif /* AF9033_PRIV_H */ -+ -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9035.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9035.c -@@ -0,0 +1,1164 @@ -+/* -+ * Afatech AF9035 DVB USB driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * Copyright (C) 2012 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#include "af9035.h" -+#include "af9033.h" -+#include "tua9001.h" -+#include "fc0011.h" -+#include "mxl5007t.h" -+#include "tda18218.h" -+ -+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -+static DEFINE_MUTEX(af9035_usb_mutex); -+static struct config af9035_config; -+static struct dvb_usb_device_properties af9035_properties[2]; -+static int af9035_properties_count = ARRAY_SIZE(af9035_properties); -+static struct af9033_config af9035_af9033_config[] = { -+ { -+ .ts_mode = AF9033_TS_MODE_USB, -+ }, { -+ .ts_mode = AF9033_TS_MODE_SERIAL, -+ } -+}; -+ -+static u16 af9035_checksum(const u8 *buf, size_t len) -+{ -+ size_t i; -+ u16 checksum = 0; -+ -+ for (i = 1; i < len; i++) { -+ if (i % 2) -+ checksum += buf[i] << 8; -+ else -+ checksum += buf[i]; -+ } -+ checksum = ~checksum; -+ -+ return checksum; -+} -+ -+static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) -+{ -+#define BUF_LEN 63 -+#define REQ_HDR_LEN 4 /* send header size */ -+#define ACK_HDR_LEN 3 /* rece header size */ -+#define CHECKSUM_LEN 2 -+#define USB_TIMEOUT 2000 -+ -+ int ret, act_len; -+ u8 buf[BUF_LEN]; -+ u32 msg_len; -+ static u8 seq; /* packet sequence number */ -+ u16 checksum, tmpsum; -+ -+ /* buffer overflow check */ -+ if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || -+ req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { -+ pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__, -+ req->wlen, req->rlen); -+ return -EINVAL; -+ } -+ -+ if (mutex_lock_interruptible(&af9035_usb_mutex) < 0) -+ return -EAGAIN; -+ -+ buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; -+ buf[1] = req->mbox; -+ buf[2] = req->cmd; -+ buf[3] = seq++; -+ if (req->wlen) -+ memcpy(&buf[4], req->wbuf, req->wlen); -+ -+ /* calc and add checksum */ -+ checksum = af9035_checksum(buf, buf[0] - 1); -+ buf[buf[0]-1] = (checksum >> 8); -+ buf[buf[0]-0] = (checksum & 0xff); -+ -+ msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ; -+ -+ /* send req */ -+ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, -+ &act_len, USB_TIMEOUT); -+ if (ret < 0) -+ err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len); -+ else -+ if (act_len != msg_len) -+ ret = -EIO; /* all data is not send */ -+ if (ret < 0) -+ goto err_mutex_unlock; -+ -+ /* no ack for those packets */ -+ if (req->cmd == CMD_FW_DL) -+ goto exit_mutex_unlock; -+ -+ /* receive ack and data if read req */ -+ msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; -+ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, -+ &act_len, USB_TIMEOUT); -+ if (ret < 0) { -+ err("recv bulk message failed=%d", ret); -+ ret = -EIO; -+ goto err_mutex_unlock; -+ } -+ if (act_len != msg_len) { -+ err("recv bulk message truncated (%d != %u)\n", -+ act_len, (unsigned int)msg_len); -+ ret = -EIO; -+ goto err_mutex_unlock; -+ } -+ -+ /* verify checksum */ -+ checksum = af9035_checksum(buf, act_len - 2); -+ tmpsum = (buf[act_len - 2] << 8) | buf[act_len - 1]; -+ if (tmpsum != checksum) { -+ err("%s: command=%02X checksum mismatch (%04X != %04X)\n", -+ __func__, req->cmd, -+ (unsigned int)tmpsum, (unsigned int)checksum); -+ ret = -EIO; -+ goto err_mutex_unlock; -+ } -+ /* check status */ -+ if (buf[2]) { -+ pr_debug("%s: command=%02x failed fw error=%d\n", __func__, -+ req->cmd, buf[2]); -+ ret = -EIO; -+ goto err_mutex_unlock; -+ } -+ -+ /* read request, copy returned data to return buf */ -+ if (req->rlen) -+ memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); -+ -+err_mutex_unlock: -+exit_mutex_unlock: -+ mutex_unlock(&af9035_usb_mutex); -+ -+ return ret; -+} -+ -+/* write multiple registers */ -+static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) -+{ -+ u8 wbuf[6 + len]; -+ u8 mbox = (reg >> 16) & 0xff; -+ struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL }; -+ -+ wbuf[0] = len; -+ wbuf[1] = 2; -+ wbuf[2] = 0; -+ wbuf[3] = 0; -+ wbuf[4] = (reg >> 8) & 0xff; -+ wbuf[5] = (reg >> 0) & 0xff; -+ memcpy(&wbuf[6], val, len); -+ -+ return af9035_ctrl_msg(d->udev, &req); -+} -+ -+/* read multiple registers */ -+static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) -+{ -+ u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff }; -+ u8 mbox = (reg >> 16) & 0xff; -+ struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val }; -+ -+ return af9035_ctrl_msg(d->udev, &req); -+} -+ -+/* write single register */ -+static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val) -+{ -+ return af9035_wr_regs(d, reg, &val, 1); -+} -+ -+/* read single register */ -+static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val) -+{ -+ return af9035_rd_regs(d, reg, val, 1); -+} -+ -+/* write single register with mask */ -+static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, -+ u8 mask) -+{ -+ int ret; -+ u8 tmp; -+ -+ /* no need for read if whole reg is written */ -+ if (mask != 0xff) { -+ ret = af9035_rd_regs(d, reg, &tmp, 1); -+ if (ret) -+ return ret; -+ -+ val &= mask; -+ tmp &= ~mask; -+ val |= tmp; -+ } -+ -+ return af9035_wr_regs(d, reg, &val, 1); -+} -+ -+static int af9035_i2c_master_xfer(struct i2c_adapter *adap, -+ struct i2c_msg msg[], int num) -+{ -+ struct dvb_usb_device *d = i2c_get_adapdata(adap); -+ int ret; -+ -+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0) -+ return -EAGAIN; -+ -+ /* -+ * I2C sub header is 5 bytes long. Meaning of those bytes are: -+ * 0: data len -+ * 1: I2C addr << 1 -+ * 2: reg addr len -+ * byte 3 and 4 can be used as reg addr -+ * 3: reg addr MSB -+ * used when reg addr len is set to 2 -+ * 4: reg addr LSB -+ * used when reg addr len is set to 1 or 2 -+ * -+ * For the simplify we do not use register addr at all. -+ * NOTE: As a firmware knows tuner type there is very small possibility -+ * there could be some tuner I2C hacks done by firmware and this may -+ * lead problems if firmware expects those bytes are used. -+ */ -+ if (num == 2 && !(msg[0].flags & I2C_M_RD) && -+ (msg[1].flags & I2C_M_RD)) { -+ if (msg[0].len > 40 || msg[1].len > 40) { -+ /* TODO: correct limits > 40 */ -+ ret = -EOPNOTSUPP; -+ } else if (msg[0].addr == af9035_af9033_config[0].i2c_addr) { -+ /* integrated demod */ -+ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | -+ msg[0].buf[2]; -+ ret = af9035_rd_regs(d, reg, &msg[1].buf[0], -+ msg[1].len); -+ } else { -+ /* I2C */ -+ u8 buf[5 + msg[0].len]; -+ struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), -+ buf, msg[1].len, msg[1].buf }; -+ buf[0] = msg[1].len; -+ buf[1] = msg[0].addr << 1; -+ buf[2] = 0x00; /* reg addr len */ -+ buf[3] = 0x00; /* reg addr MSB */ -+ buf[4] = 0x00; /* reg addr LSB */ -+ memcpy(&buf[5], msg[0].buf, msg[0].len); -+ ret = af9035_ctrl_msg(d->udev, &req); -+ } -+ } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { -+ if (msg[0].len > 40) { -+ /* TODO: correct limits > 40 */ -+ ret = -EOPNOTSUPP; -+ } else if (msg[0].addr == af9035_af9033_config[0].i2c_addr) { -+ /* integrated demod */ -+ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | -+ msg[0].buf[2]; -+ ret = af9035_wr_regs(d, reg, &msg[0].buf[3], -+ msg[0].len - 3); -+ } else { -+ /* I2C */ -+ u8 buf[5 + msg[0].len]; -+ struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf, -+ 0, NULL }; -+ buf[0] = msg[0].len; -+ buf[1] = msg[0].addr << 1; -+ buf[2] = 0x00; /* reg addr len */ -+ buf[3] = 0x00; /* reg addr MSB */ -+ buf[4] = 0x00; /* reg addr LSB */ -+ memcpy(&buf[5], msg[0].buf, msg[0].len); -+ ret = af9035_ctrl_msg(d->udev, &req); -+ } -+ } else { -+ /* -+ * We support only two kind of I2C transactions: -+ * 1) 1 x read + 1 x write -+ * 2) 1 x write -+ */ -+ ret = -EOPNOTSUPP; -+ } -+ -+ mutex_unlock(&d->i2c_mutex); -+ -+ if (ret < 0) -+ return ret; -+ else -+ return num; -+} -+ -+static u32 af9035_i2c_functionality(struct i2c_adapter *adapter) -+{ -+ return I2C_FUNC_I2C; -+} -+ -+static struct i2c_algorithm af9035_i2c_algo = { -+ .master_xfer = af9035_i2c_master_xfer, -+ .functionality = af9035_i2c_functionality, -+}; -+ -+static int af9035_init(struct dvb_usb_device *d) -+{ -+ int ret, i; -+ u16 frame_size = 87 * 188 / 4; -+ u8 packet_size = 512 / 4; -+ struct reg_val_mask tab[] = { -+ { 0x80f99d, 0x01, 0x01 }, -+ { 0x80f9a4, 0x01, 0x01 }, -+ { 0x00dd11, 0x00, 0x20 }, -+ { 0x00dd11, 0x00, 0x40 }, -+ { 0x00dd13, 0x00, 0x20 }, -+ { 0x00dd13, 0x00, 0x40 }, -+ { 0x00dd11, 0x20, 0x20 }, -+ { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, -+ { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, -+ { 0x00dd0c, packet_size, 0xff}, -+ { 0x00dd11, af9035_config.dual_mode << 6, 0x40 }, -+ { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, -+ { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, -+ { 0x00dd0d, packet_size, 0xff }, -+ { 0x80f9a3, 0x00, 0x01 }, -+ { 0x80f9cd, 0x00, 0x01 }, -+ { 0x80f99d, 0x00, 0x01 }, -+ { 0x80f9a4, 0x00, 0x01 }, -+ }; -+ -+ pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", -+ __func__, d->udev->speed, frame_size, packet_size); -+ -+ /* init endpoints */ -+ for (i = 0; i < ARRAY_SIZE(tab); i++) { -+ ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, -+ tab[i].mask); -+ if (ret < 0) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9035_identify_state(struct usb_device *udev, -+ struct dvb_usb_device_properties *props, -+ struct dvb_usb_device_description **desc, -+ int *cold) -+{ -+ int ret; -+ u8 wbuf[1] = { 1 }; -+ u8 rbuf[4]; -+ struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, -+ sizeof(rbuf), rbuf }; -+ -+ ret = af9035_ctrl_msg(udev, &req); -+ if (ret < 0) -+ goto err; -+ -+ pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__, -+ rbuf[0], rbuf[1], rbuf[2], rbuf[3]); -+ if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) -+ *cold = 0; -+ else -+ *cold = 1; -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9035_download_firmware(struct usb_device *udev, -+ const struct firmware *fw) -+{ -+ int ret, i, j, len; -+ u8 wbuf[1]; -+ u8 rbuf[4]; -+ struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; -+ struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL }; -+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; -+ u8 hdr_core; -+ u16 hdr_addr, hdr_data_len, hdr_checksum; -+ #define MAX_DATA 57 -+ #define HDR_SIZE 7 -+ -+ /* -+ * Thanks to Daniel Glöckner about that info! -+ * -+ * byte 0: MCS 51 core -+ * There are two inside the AF9035 (1=Link and 2=OFDM) with separate -+ * address spaces -+ * byte 1-2: Big endian destination address -+ * byte 3-4: Big endian number of data bytes following the header -+ * byte 5-6: Big endian header checksum, apparently ignored by the chip -+ * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256) -+ */ -+ -+ for (i = fw->size; i > HDR_SIZE;) { -+ hdr_core = fw->data[fw->size - i + 0]; -+ hdr_addr = fw->data[fw->size - i + 1] << 8; -+ hdr_addr |= fw->data[fw->size - i + 2] << 0; -+ hdr_data_len = fw->data[fw->size - i + 3] << 8; -+ hdr_data_len |= fw->data[fw->size - i + 4] << 0; -+ hdr_checksum = fw->data[fw->size - i + 5] << 8; -+ hdr_checksum |= fw->data[fw->size - i + 6] << 0; -+ -+ pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n", -+ __func__, hdr_core, hdr_addr, hdr_data_len, -+ hdr_checksum); -+ -+ if (((hdr_core != 1) && (hdr_core != 2)) || -+ (hdr_data_len > i)) { -+ pr_debug("%s: bad firmware\n", __func__); -+ break; -+ } -+ -+ /* download begin packet */ -+ req.cmd = CMD_FW_DL_BEGIN; -+ ret = af9035_ctrl_msg(udev, &req); -+ if (ret < 0) -+ goto err; -+ -+ /* download firmware packet(s) */ -+ for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) { -+ len = j; -+ if (len > MAX_DATA) -+ len = MAX_DATA; -+ req_fw_dl.wlen = len; -+ req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i + -+ HDR_SIZE + hdr_data_len - j]; -+ ret = af9035_ctrl_msg(udev, &req_fw_dl); -+ if (ret < 0) -+ goto err; -+ } -+ -+ /* download end packet */ -+ req.cmd = CMD_FW_DL_END; -+ ret = af9035_ctrl_msg(udev, &req); -+ if (ret < 0) -+ goto err; -+ -+ i -= hdr_data_len + HDR_SIZE; -+ -+ pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i); -+ } -+ -+ /* firmware loaded, request boot */ -+ req.cmd = CMD_FW_BOOT; -+ ret = af9035_ctrl_msg(udev, &req); -+ if (ret < 0) -+ goto err; -+ -+ /* ensure firmware starts */ -+ wbuf[0] = 1; -+ ret = af9035_ctrl_msg(udev, &req_fw_ver); -+ if (ret < 0) -+ goto err; -+ -+ if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { -+ info("firmware did not run"); -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2], -+ rbuf[3]); -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9035_download_firmware_it9135(struct usb_device *udev, -+ const struct firmware *fw) -+{ -+ int ret, i, i_prev; -+ u8 wbuf[1]; -+ u8 rbuf[4]; -+ struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; -+ struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; -+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; -+ #define HDR_SIZE 7 -+ -+ /* -+ * There seems to be following firmware header. Meaning of bytes 0-3 -+ * is unknown. -+ * -+ * 0: 3 -+ * 1: 0, 1 -+ * 2: 0 -+ * 3: 1, 2, 3 -+ * 4: addr MSB -+ * 5: addr LSB -+ * 6: count of data bytes ? -+ */ -+ -+ for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) { -+ if (i == fw->size || -+ (fw->data[i + 0] == 0x03 && -+ (fw->data[i + 1] == 0x00 || -+ fw->data[i + 1] == 0x01) && -+ fw->data[i + 2] == 0x00)) { -+ req_fw_dl.wlen = i - i_prev; -+ req_fw_dl.wbuf = (u8 *) &fw->data[i_prev]; -+ i_prev = i; -+ ret = af9035_ctrl_msg(udev, &req_fw_dl); -+ if (ret < 0) -+ goto err; -+ -+ pr_debug("%s: data uploaded=%d\n", __func__, i); -+ } -+ } -+ -+ /* firmware loaded, request boot */ -+ req.cmd = CMD_FW_BOOT; -+ ret = af9035_ctrl_msg(udev, &req); -+ if (ret < 0) -+ goto err; -+ -+ /* ensure firmware starts */ -+ wbuf[0] = 1; -+ ret = af9035_ctrl_msg(udev, &req_fw_ver); -+ if (ret < 0) -+ goto err; -+ -+ if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { -+ info("firmware did not run"); -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2], -+ rbuf[3]); -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+/* abuse that callback as there is no better one for reading eeprom */ -+static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) -+{ -+ int ret, i, eeprom_shift = 0; -+ u8 tmp; -+ u16 tmp16; -+ -+ /* check if there is dual tuners */ -+ ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ af9035_config.dual_mode = tmp; -+ pr_debug("%s: dual mode=%d\n", __func__, af9035_config.dual_mode); -+ -+ for (i = 0; i < af9035_properties[0].num_adapters; i++) { -+ /* tuner */ -+ ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ af9035_af9033_config[i].tuner = tmp; -+ pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp); -+ -+ switch (tmp) { -+ case AF9033_TUNER_TUA9001: -+ case AF9033_TUNER_FC0011: -+ case AF9033_TUNER_MXL5007T: -+ case AF9033_TUNER_TDA18218: -+ af9035_af9033_config[i].spec_inv = 1; -+ break; -+ default: -+ af9035_config.hw_not_supported = true; -+ warn("tuner ID=%02x not supported, please report!", -+ tmp); -+ }; -+ -+ /* tuner IF frequency */ -+ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ tmp16 = tmp; -+ -+ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ tmp16 |= tmp << 8; -+ -+ pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16); -+ -+ eeprom_shift = 0x10; /* shift for the 2nd tuner params */ -+ } -+ -+ /* get demod clock */ -+ ret = af9035_rd_reg(d, 0x00d800, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ tmp = (tmp >> 0) & 0x0f; -+ -+ for (i = 0; i < af9035_properties[0].num_adapters; i++) -+ af9035_af9033_config[i].clock = clock_lut[tmp]; -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+/* abuse that callback as there is no better one for reading eeprom */ -+static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6]) -+{ -+ int ret, i; -+ u8 tmp; -+ -+ af9035_config.dual_mode = 0; -+ -+ /* get demod clock */ -+ ret = af9035_rd_reg(d, 0x00d800, &tmp); -+ if (ret < 0) -+ goto err; -+ -+ tmp = (tmp >> 0) & 0x0f; -+ -+ for (i = 0; i < af9035_properties[0].num_adapters; i++) -+ af9035_af9033_config[i].clock = clock_lut_it9135[tmp]; -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, -+ int cmd, int arg) -+{ -+ int ret; -+ -+ switch (cmd) { -+ case FC0011_FE_CALLBACK_POWER: -+ /* Tuner enable */ -+ ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1); -+ if (ret < 0) -+ goto err; -+ -+ /* LED */ -+ ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1); -+ if (ret < 0) -+ goto err; -+ -+ usleep_range(10000, 50000); -+ break; -+ case FC0011_FE_CALLBACK_RESET: -+ ret = af9035_wr_reg(d, 0xd8e9, 1); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg(d, 0xd8e8, 1); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg(d, 0xd8e7, 1); -+ if (ret < 0) -+ goto err; -+ -+ usleep_range(10000, 20000); -+ -+ ret = af9035_wr_reg(d, 0xd8e7, 0); -+ if (ret < 0) -+ goto err; -+ -+ usleep_range(10000, 20000); -+ break; -+ default: -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) -+{ -+ switch (af9035_af9033_config[0].tuner) { -+ case AF9033_TUNER_FC0011: -+ return af9035_fc0011_tuner_callback(d, cmd, arg); -+ default: -+ break; -+ } -+ -+ return -ENODEV; -+} -+ -+static int af9035_frontend_callback(void *adapter_priv, int component, -+ int cmd, int arg) -+{ -+ struct i2c_adapter *adap = adapter_priv; -+ struct dvb_usb_device *d = i2c_get_adapdata(adap); -+ -+ switch (component) { -+ case DVB_FRONTEND_COMPONENT_TUNER: -+ return af9035_tuner_callback(d, cmd, arg); -+ default: -+ break; -+ } -+ -+ return -EINVAL; -+} -+ -+static int af9035_frontend_attach(struct dvb_usb_adapter *adap) -+{ -+ int ret; -+ -+ if (af9035_config.hw_not_supported) { -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ if (adap->id == 0) { -+ ret = af9035_wr_reg(adap->dev, 0x00417f, -+ af9035_af9033_config[1].i2c_addr); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg(adap->dev, 0x00d81a, -+ af9035_config.dual_mode); -+ if (ret < 0) -+ goto err; -+ } -+ -+ /* attach demodulator */ -+ adap->fe_adap[0].fe = dvb_attach(af9033_attach, -+ &af9035_af9033_config[adap->id], &adap->dev->i2c_adap); -+ if (adap->fe_adap[0].fe == NULL) { -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ /* disable I2C-gate */ -+ adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL; -+ adap->fe_adap[0].fe->callback = af9035_frontend_callback; -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+static struct tua9001_config af9035_tua9001_config = { -+ .i2c_addr = 0x60, -+}; -+ -+static const struct fc0011_config af9035_fc0011_config = { -+ .i2c_address = 0x60, -+}; -+ -+static struct mxl5007t_config af9035_mxl5007t_config = { -+ .xtal_freq_hz = MxL_XTAL_24_MHZ, -+ .if_freq_hz = MxL_IF_4_57_MHZ, -+ .invert_if = 0, -+ .loop_thru_enable = 0, -+ .clk_out_enable = 0, -+ .clk_out_amp = MxL_CLKOUT_AMP_0_94V, -+}; -+ -+static struct tda18218_config af9035_tda18218_config = { -+ .i2c_address = 0x60, -+ .i2c_wr_max = 21, -+}; -+ -+static int af9035_tuner_attach(struct dvb_usb_adapter *adap) -+{ -+ int ret; -+ struct dvb_frontend *fe; -+ -+ switch (af9035_af9033_config[adap->id].tuner) { -+ case AF9033_TUNER_TUA9001: -+ /* AF9035 gpiot3 = TUA9001 RESETN -+ AF9035 gpiot2 = TUA9001 RXEN */ -+ -+ /* configure gpiot2 and gpiot2 as output */ -+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ /* reset tuner */ -+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ usleep_range(2000, 20000); -+ -+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ /* activate tuner RX */ -+ /* TODO: use callback for TUA9001 RXEN */ -+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01); -+ if (ret < 0) -+ goto err; -+ -+ /* attach tuner */ -+ fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe, -+ &adap->dev->i2c_adap, &af9035_tua9001_config); -+ break; -+ case AF9033_TUNER_FC0011: -+ fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe, -+ &adap->dev->i2c_adap, &af9035_fc0011_config); -+ break; -+ case AF9033_TUNER_MXL5007T: -+ ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1); -+ if (ret < 0) -+ goto err; -+ ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1); -+ if (ret < 0) -+ goto err; -+ ret = af9035_wr_reg(adap->dev, 0x00d8df, 0); -+ if (ret < 0) -+ goto err; -+ -+ msleep(30); -+ -+ ret = af9035_wr_reg(adap->dev, 0x00d8df, 1); -+ if (ret < 0) -+ goto err; -+ -+ msleep(300); -+ -+ ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1); -+ if (ret < 0) -+ goto err; -+ ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1); -+ if (ret < 0) -+ goto err; -+ ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0); -+ if (ret < 0) -+ goto err; -+ ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1); -+ if (ret < 0) -+ goto err; -+ ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1); -+ if (ret < 0) -+ goto err; -+ ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1); -+ if (ret < 0) -+ goto err; -+ -+ /* attach tuner */ -+ fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, -+ &adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config); -+ break; -+ case AF9033_TUNER_TDA18218: -+ /* attach tuner */ -+ fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe, -+ &adap->dev->i2c_adap, &af9035_tda18218_config); -+ break; -+ default: -+ fe = NULL; -+ } -+ -+ if (fe == NULL) { -+ ret = -ENODEV; -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+enum af9035_id_entry { -+ AF9035_15A4_9035, -+ AF9035_15A4_1001, -+ AF9035_0CCD_0093, -+ AF9035_07CA_A835, -+ AF9035_07CA_B835, -+ AF9035_07CA_1867, -+ AF9035_07CA_A867, -+ AF9035_07CA_0825, -+}; -+ -+static struct usb_device_id af9035_id[] = { -+ [AF9035_15A4_9035] = { -+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035)}, -+ [AF9035_15A4_1001] = { -+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_2)}, -+ [AF9035_0CCD_0093] = { -+ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)}, -+ [AF9035_07CA_A835] = { -+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)}, -+ [AF9035_07CA_B835] = { -+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)}, -+ [AF9035_07CA_1867] = { -+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)}, -+ [AF9035_07CA_A867] = { -+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)}, -+ [AF9035_07CA_0825] = { -+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)}, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(usb, af9035_id); -+ -+static struct dvb_usb_device_properties af9035_properties[] = { -+ { -+ .caps = DVB_USB_IS_AN_I2C_ADAPTER, -+ -+ .usb_ctrl = DEVICE_SPECIFIC, -+ .download_firmware = af9035_download_firmware, -+ .firmware = "dvb-usb-af9035-02.fw", -+ .no_reconnect = 1, -+ -+ .num_adapters = 1, -+ .adapter = { -+ { -+ .num_frontends = 1, -+ .fe = { -+ { -+ .frontend_attach = af9035_frontend_attach, -+ .tuner_attach = af9035_tuner_attach, -+ .stream = { -+ .type = USB_BULK, -+ .count = 6, -+ .endpoint = 0x84, -+ .u = { -+ .bulk = { -+ .buffersize = (87 * 188), -+ } -+ } -+ } -+ } -+ } -+ } -+ }, -+ -+ .identify_state = af9035_identify_state, -+ .read_mac_address = af9035_read_mac_address, -+ -+ .i2c_algo = &af9035_i2c_algo, -+ -+ .num_device_descs = 5, -+ .devices = { -+ { -+ .name = "Afatech AF9035 reference design", -+ .cold_ids = { -+ &af9035_id[AF9035_15A4_9035], -+ &af9035_id[AF9035_15A4_1001], -+ }, -+ }, { -+ .name = "TerraTec Cinergy T Stick", -+ .cold_ids = { -+ &af9035_id[AF9035_0CCD_0093], -+ }, -+ }, { -+ .name = "AVerMedia AVerTV Volar HD/PRO (A835)", -+ .cold_ids = { -+ &af9035_id[AF9035_07CA_A835], -+ &af9035_id[AF9035_07CA_B835], -+ }, -+ }, { -+ .name = "AVerMedia HD Volar (A867)", -+ .cold_ids = { -+ &af9035_id[AF9035_07CA_1867], -+ &af9035_id[AF9035_07CA_A867], -+ }, -+ }, { -+ .name = "AVerMedia Twinstar (A825)", -+ .cold_ids = { -+ &af9035_id[AF9035_07CA_0825], -+ }, -+ }, -+ } -+ }, -+ { -+ .caps = DVB_USB_IS_AN_I2C_ADAPTER, -+ -+ .usb_ctrl = DEVICE_SPECIFIC, -+ .download_firmware = af9035_download_firmware_it9135, -+ .firmware = "dvb-usb-it9135-01.fw", -+ .no_reconnect = 1, -+ -+ .num_adapters = 1, -+ .adapter = { -+ { -+ .num_frontends = 1, -+ .fe = { -+ { -+ .frontend_attach = af9035_frontend_attach, -+ .tuner_attach = af9035_tuner_attach, -+ .stream = { -+ .type = USB_BULK, -+ .count = 6, -+ .endpoint = 0x84, -+ .u = { -+ .bulk = { -+ .buffersize = (87 * 188), -+ } -+ } -+ } -+ } -+ } -+ } -+ }, -+ -+ .identify_state = af9035_identify_state, -+ .read_mac_address = af9035_read_mac_address_it9135, -+ -+ .i2c_algo = &af9035_i2c_algo, -+ -+ .num_device_descs = 0, /* disabled as no support for IT9135 */ -+ .devices = { -+ { -+ .name = "ITE Tech. IT9135 reference design", -+ }, -+ } -+ }, -+}; -+ -+static int af9035_usb_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ int ret, i; -+ struct dvb_usb_device *d = NULL; -+ struct usb_device *udev; -+ bool found; -+ -+ pr_debug("%s: interface=%d\n", __func__, -+ intf->cur_altsetting->desc.bInterfaceNumber); -+ -+ /* interface 0 is used by DVB-T receiver and -+ interface 1 is for remote controller (HID) */ -+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0) -+ return 0; -+ -+ /* Dynamic USB ID support. Replaces first device ID with current one. */ -+ udev = interface_to_usbdev(intf); -+ -+ for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) { -+ if (af9035_id[i].idVendor == -+ le16_to_cpu(udev->descriptor.idVendor) && -+ af9035_id[i].idProduct == -+ le16_to_cpu(udev->descriptor.idProduct)) { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) { -+ pr_debug("%s: using dynamic ID %04x:%04x\n", __func__, -+ le16_to_cpu(udev->descriptor.idVendor), -+ le16_to_cpu(udev->descriptor.idProduct)); -+ af9035_properties[0].devices[0].cold_ids[0]->idVendor = -+ le16_to_cpu(udev->descriptor.idVendor); -+ af9035_properties[0].devices[0].cold_ids[0]->idProduct = -+ le16_to_cpu(udev->descriptor.idProduct); -+ } -+ -+ -+ for (i = 0; i < af9035_properties_count; i++) { -+ ret = dvb_usb_device_init(intf, &af9035_properties[i], -+ THIS_MODULE, &d, adapter_nr); -+ -+ if (ret == -ENODEV) -+ continue; -+ else -+ break; -+ } -+ -+ if (ret < 0) -+ goto err; -+ -+ if (d) { -+ ret = af9035_init(d); -+ if (ret < 0) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ pr_debug("%s: failed=%d\n", __func__, ret); -+ -+ return ret; -+} -+ -+/* usb specific object needed to register this driver with the usb subsystem */ -+static struct usb_driver af9035_usb_driver = { -+ .name = "dvb_usb_af9035", -+ .probe = af9035_usb_probe, -+ .disconnect = dvb_usb_device_exit, -+ .id_table = af9035_id, -+}; -+ -+module_usb_driver(af9035_usb_driver); -+ -+MODULE_AUTHOR("Antti Palosaari "); -+MODULE_DESCRIPTION("Afatech AF9035 driver"); -+MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9035.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/dvb/dvb-usb/af9035.h -@@ -0,0 +1,120 @@ -+/* -+ * Afatech AF9035 DVB USB driver -+ * -+ * Copyright (C) 2009 Antti Palosaari -+ * Copyright (C) 2012 Antti Palosaari -+ * -+ * 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., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ */ -+ -+#ifndef AF9035_H -+#define AF9035_H -+ -+/* prefix for dvb-usb log writings */ -+#define DVB_USB_LOG_PREFIX "af9035" -+ -+#include "dvb-usb.h" -+ -+struct reg_val { -+ u32 reg; -+ u8 val; -+}; -+ -+struct reg_val_mask { -+ u32 reg; -+ u8 val; -+ u8 mask; -+}; -+ -+struct usb_req { -+ u8 cmd; -+ u8 mbox; -+ u8 wlen; -+ u8 *wbuf; -+ u8 rlen; -+ u8 *rbuf; -+}; -+ -+struct config { -+ bool dual_mode; -+ bool hw_not_supported; -+}; -+ -+struct fw_segment { -+#define SEGMENT_FW_DL 0 -+#define SEGMENT_ROM_COPY 1 -+#define SEGMENT_DIRECT_CMD 2 -+ u8 type; -+ u32 len; -+}; -+ -+struct fw_header { -+#define SEGMENT_MAX_COUNT 6 -+ u8 segment_count; -+ struct fw_segment segment[SEGMENT_MAX_COUNT]; -+}; -+ -+u32 clock_lut[] = { -+ 20480000, /* FPGA */ -+ 16384000, /* 16.38 MHz */ -+ 20480000, /* 20.48 MHz */ -+ 36000000, /* 36.00 MHz */ -+ 30000000, /* 30.00 MHz */ -+ 26000000, /* 26.00 MHz */ -+ 28000000, /* 28.00 MHz */ -+ 32000000, /* 32.00 MHz */ -+ 34000000, /* 34.00 MHz */ -+ 24000000, /* 24.00 MHz */ -+ 22000000, /* 22.00 MHz */ -+ 12000000, /* 12.00 MHz */ -+}; -+ -+u32 clock_lut_it9135[] = { -+ 12000000, /* 12.00 MHz */ -+ 20480000, /* 20.48 MHz */ -+ 36000000, /* 36.00 MHz */ -+ 30000000, /* 30.00 MHz */ -+ 26000000, /* 26.00 MHz */ -+ 28000000, /* 28.00 MHz */ -+ 32000000, /* 32.00 MHz */ -+ 34000000, /* 34.00 MHz */ -+ 24000000, /* 24.00 MHz */ -+ 22000000, /* 22.00 MHz */ -+}; -+ -+/* EEPROM locations */ -+#define EEPROM_IR_MODE 0x430d -+#define EEPROM_DUAL_MODE 0x4326 -+#define EEPROM_IR_TYPE 0x4329 -+#define EEPROM_1_IFFREQ_L 0x432d -+#define EEPROM_1_IFFREQ_H 0x432e -+#define EEPROM_1_TUNER_ID 0x4331 -+#define EEPROM_2_IFFREQ_L 0x433d -+#define EEPROM_2_IFFREQ_H 0x433e -+#define EEPROM_2_TUNER_ID 0x4341 -+ -+/* USB commands */ -+#define CMD_MEM_RD 0x00 -+#define CMD_MEM_WR 0x01 -+#define CMD_I2C_RD 0x02 -+#define CMD_I2C_WR 0x03 -+#define CMD_FW_DL 0x21 -+#define CMD_FW_QUERYINFO 0x22 -+#define CMD_FW_BOOT 0x23 -+#define CMD_FW_DL_BEGIN 0x24 -+#define CMD_FW_DL_END 0x25 -+#define CMD_FW_SCATTER_WR 0x29 -+ -+#endif -Index: linux-3.3.x86_64/MAINTAINERS -=================================================================== ---- linux-3.3.x86_64.orig/MAINTAINERS -+++ linux-3.3.x86_64/MAINTAINERS -@@ -2659,6 +2659,13 @@ S: Maintained - F: Documentation/hwmon/f71805f - F: drivers/hwmon/f71805f.c - -+FC0011 TUNER DRIVER -+M: Michael Buesch -+L: linux-media@vger.kernel.org -+S: Maintained -+F: drivers/media/common/tuners/fc0011.h -+F: drivers/media/common/tuners/fc0011.c -+ - FANOTIFY - M: Eric Paris - S: Maintained -Index: linux-3.3.x86_64/drivers/media/common/tuners/fc0011.c -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/common/tuners/fc0011.c -@@ -0,0 +1,524 @@ -+/* -+ * Fitipower FC0011 tuner driver -+ * -+ * Copyright (C) 2012 Michael Buesch -+ * -+ * Derived from FC0012 tuner driver: -+ * Copyright (C) 2012 Hans-Frieder Vogt -+ * -+ * 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 "fc0011.h" -+ -+ -+/* Tuner registers */ -+enum { -+ FC11_REG_0, -+ FC11_REG_FA, /* FA */ -+ FC11_REG_FP, /* FP */ -+ FC11_REG_XINHI, /* XIN high 8 bit */ -+ FC11_REG_XINLO, /* XIN low 8 bit */ -+ FC11_REG_VCO, /* VCO */ -+ FC11_REG_VCOSEL, /* VCO select */ -+ FC11_REG_7, /* Unknown tuner reg 7 */ -+ FC11_REG_8, /* Unknown tuner reg 8 */ -+ FC11_REG_9, -+ FC11_REG_10, /* Unknown tuner reg 10 */ -+ FC11_REG_11, /* Unknown tuner reg 11 */ -+ FC11_REG_12, -+ FC11_REG_RCCAL, /* RC calibrate */ -+ FC11_REG_VCOCAL, /* VCO calibrate */ -+ FC11_REG_15, -+ FC11_REG_16, /* Unknown tuner reg 16 */ -+ FC11_REG_17, -+ -+ FC11_NR_REGS, /* Number of registers */ -+}; -+ -+enum FC11_REG_VCOSEL_bits { -+ FC11_VCOSEL_2 = 0x08, /* VCO select 2 */ -+ FC11_VCOSEL_1 = 0x10, /* VCO select 1 */ -+ FC11_VCOSEL_CLKOUT = 0x20, /* Fix clock out */ -+ FC11_VCOSEL_BW7M = 0x40, /* 7MHz bw */ -+ FC11_VCOSEL_BW6M = 0x80, /* 6MHz bw */ -+}; -+ -+enum FC11_REG_RCCAL_bits { -+ FC11_RCCAL_FORCE = 0x10, /* force */ -+}; -+ -+enum FC11_REG_VCOCAL_bits { -+ FC11_VCOCAL_RUN = 0, /* VCO calibration run */ -+ FC11_VCOCAL_VALUEMASK = 0x3F, /* VCO calibration value mask */ -+ FC11_VCOCAL_OK = 0x40, /* VCO calibration Ok */ -+ FC11_VCOCAL_RESET = 0x80, /* VCO calibration reset */ -+}; -+ -+ -+struct fc0011_priv { -+ struct i2c_adapter *i2c; -+ u8 addr; -+ -+ u32 frequency; -+ u32 bandwidth; -+}; -+ -+ -+static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val) -+{ -+ u8 buf[2] = { reg, val }; -+ struct i2c_msg msg = { .addr = priv->addr, -+ .flags = 0, .buf = buf, .len = 2 }; -+ -+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) { -+ dev_err(&priv->i2c->dev, -+ "I2C write reg failed, reg: %02x, val: %02x\n", -+ reg, val); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val) -+{ -+ u8 dummy; -+ struct i2c_msg msg[2] = { -+ { .addr = priv->addr, -+ .flags = 0, .buf = ®, .len = 1 }, -+ { .addr = priv->addr, -+ .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 }, -+ }; -+ -+ if (i2c_transfer(priv->i2c, msg, 2) != 2) { -+ dev_err(&priv->i2c->dev, -+ "I2C read failed, reg: %02x\n", reg); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int fc0011_release(struct dvb_frontend *fe) -+{ -+ kfree(fe->tuner_priv); -+ fe->tuner_priv = NULL; -+ -+ return 0; -+} -+ -+static int fc0011_init(struct dvb_frontend *fe) -+{ -+ struct fc0011_priv *priv = fe->tuner_priv; -+ int err; -+ -+ if (WARN_ON(!fe->callback)) -+ return -EINVAL; -+ -+ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, -+ FC0011_FE_CALLBACK_POWER, priv->addr); -+ if (err) { -+ dev_err(&priv->i2c->dev, "Power-on callback failed\n"); -+ return err; -+ } -+ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, -+ FC0011_FE_CALLBACK_RESET, priv->addr); -+ if (err) { -+ dev_err(&priv->i2c->dev, "Reset callback failed\n"); -+ return err; -+ } -+ -+ return 0; -+} -+ -+/* Initiate VCO calibration */ -+static int fc0011_vcocal_trigger(struct fc0011_priv *priv) -+{ -+ int err; -+ -+ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET); -+ if (err) -+ return err; -+ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+/* Read VCO calibration value */ -+static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value) -+{ -+ int err; -+ -+ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); -+ if (err) -+ return err; -+ usleep_range(10000, 20000); -+ err = fc0011_readreg(priv, FC11_REG_VCOCAL, value); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static int fc0011_set_params(struct dvb_frontend *fe) -+{ -+ struct dtv_frontend_properties *p = &fe->dtv_property_cache; -+ struct fc0011_priv *priv = fe->tuner_priv; -+ int err; -+ unsigned int i, vco_retries; -+ u32 freq = p->frequency / 1000; -+ u32 bandwidth = p->bandwidth_hz / 1000; -+ u32 fvco, xin, xdiv, xdivr; -+ u16 frac; -+ u8 fa, fp, vco_sel, vco_cal; -+ u8 regs[FC11_NR_REGS] = { }; -+ -+ regs[FC11_REG_7] = 0x0F; -+ regs[FC11_REG_8] = 0x3E; -+ regs[FC11_REG_10] = 0xB8; -+ regs[FC11_REG_11] = 0x80; -+ regs[FC11_REG_RCCAL] = 0x04; -+ err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); -+ err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); -+ err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); -+ err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); -+ err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); -+ if (err) -+ return -EIO; -+ -+ /* Set VCO freq and VCO div */ -+ if (freq < 54000) { -+ fvco = freq * 64; -+ regs[FC11_REG_VCO] = 0x82; -+ } else if (freq < 108000) { -+ fvco = freq * 32; -+ regs[FC11_REG_VCO] = 0x42; -+ } else if (freq < 216000) { -+ fvco = freq * 16; -+ regs[FC11_REG_VCO] = 0x22; -+ } else if (freq < 432000) { -+ fvco = freq * 8; -+ regs[FC11_REG_VCO] = 0x12; -+ } else { -+ fvco = freq * 4; -+ regs[FC11_REG_VCO] = 0x0A; -+ } -+ -+ /* Calc XIN. The PLL reference frequency is 18 MHz. */ -+ xdiv = fvco / 18000; -+ frac = fvco - xdiv * 18000; -+ frac = (frac << 15) / 18000; -+ if (frac >= 16384) -+ frac += 32786; -+ if (!frac) -+ xin = 0; -+ else if (frac < 511) -+ xin = 512; -+ else if (frac < 65026) -+ xin = frac; -+ else -+ xin = 65024; -+ regs[FC11_REG_XINHI] = xin >> 8; -+ regs[FC11_REG_XINLO] = xin; -+ -+ /* Calc FP and FA */ -+ xdivr = xdiv; -+ if (fvco - xdiv * 18000 >= 9000) -+ xdivr += 1; /* round */ -+ fp = xdivr / 8; -+ fa = xdivr - fp * 8; -+ if (fa < 2) { -+ fp -= 1; -+ fa += 8; -+ } -+ if (fp > 0x1F) { -+ fp &= 0x1F; -+ fa &= 0xF; -+ } -+ if (fa >= fp) { -+ dev_warn(&priv->i2c->dev, -+ "fa %02X >= fp %02X, but trying to continue\n", -+ (unsigned int)(u8)fa, (unsigned int)(u8)fp); -+ } -+ regs[FC11_REG_FA] = fa; -+ regs[FC11_REG_FP] = fp; -+ -+ /* Select bandwidth */ -+ switch (bandwidth) { -+ case 8000: -+ break; -+ case 7000: -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M; -+ break; -+ default: -+ dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. " -+ "Using 6000 kHz.\n", -+ bandwidth); -+ bandwidth = 6000; -+ /* fallthrough */ -+ case 6000: -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M; -+ break; -+ } -+ -+ /* Pre VCO select */ -+ if (fvco < 2320000) { -+ vco_sel = 0; -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ } else if (fvco < 3080000) { -+ vco_sel = 1; -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; -+ } else { -+ vco_sel = 2; -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; -+ } -+ -+ /* Fix for low freqs */ -+ if (freq < 45000) { -+ regs[FC11_REG_FA] = 0x6; -+ regs[FC11_REG_FP] = 0x11; -+ } -+ -+ /* Clock out fix */ -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT; -+ -+ /* Write the cached registers */ -+ for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) { -+ err = fc0011_writereg(priv, i, regs[i]); -+ if (err) -+ return err; -+ } -+ -+ /* VCO calibration */ -+ err = fc0011_vcocal_trigger(priv); -+ if (err) -+ return err; -+ err = fc0011_vcocal_read(priv, &vco_cal); -+ if (err) -+ return err; -+ vco_retries = 0; -+ while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) { -+ /* Reset the tuner and try again */ -+ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, -+ FC0011_FE_CALLBACK_RESET, priv->addr); -+ if (err) { -+ dev_err(&priv->i2c->dev, "Failed to reset tuner\n"); -+ return err; -+ } -+ /* Reinit tuner config */ -+ err = 0; -+ for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) -+ err |= fc0011_writereg(priv, i, regs[i]); -+ err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); -+ err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); -+ err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); -+ err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); -+ err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); -+ if (err) -+ return -EIO; -+ /* VCO calibration */ -+ err = fc0011_vcocal_trigger(priv); -+ if (err) -+ return err; -+ err = fc0011_vcocal_read(priv, &vco_cal); -+ if (err) -+ return err; -+ vco_retries++; -+ } -+ if (!(vco_cal & FC11_VCOCAL_OK)) { -+ dev_err(&priv->i2c->dev, -+ "Failed to read VCO calibration value (got %02X)\n", -+ (unsigned int)vco_cal); -+ return -EIO; -+ } -+ vco_cal &= FC11_VCOCAL_VALUEMASK; -+ -+ switch (vco_sel) { -+ case 0: -+ if (vco_cal < 8) { -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; -+ err = fc0011_writereg(priv, FC11_REG_VCOSEL, -+ regs[FC11_REG_VCOSEL]); -+ if (err) -+ return err; -+ err = fc0011_vcocal_trigger(priv); -+ if (err) -+ return err; -+ } else { -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ err = fc0011_writereg(priv, FC11_REG_VCOSEL, -+ regs[FC11_REG_VCOSEL]); -+ if (err) -+ return err; -+ } -+ break; -+ case 1: -+ if (vco_cal < 5) { -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; -+ err = fc0011_writereg(priv, FC11_REG_VCOSEL, -+ regs[FC11_REG_VCOSEL]); -+ if (err) -+ return err; -+ err = fc0011_vcocal_trigger(priv); -+ if (err) -+ return err; -+ } else if (vco_cal <= 48) { -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; -+ err = fc0011_writereg(priv, FC11_REG_VCOSEL, -+ regs[FC11_REG_VCOSEL]); -+ if (err) -+ return err; -+ } else { -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ err = fc0011_writereg(priv, FC11_REG_VCOSEL, -+ regs[FC11_REG_VCOSEL]); -+ if (err) -+ return err; -+ err = fc0011_vcocal_trigger(priv); -+ if (err) -+ return err; -+ } -+ break; -+ case 2: -+ if (vco_cal > 53) { -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; -+ err = fc0011_writereg(priv, FC11_REG_VCOSEL, -+ regs[FC11_REG_VCOSEL]); -+ if (err) -+ return err; -+ err = fc0011_vcocal_trigger(priv); -+ if (err) -+ return err; -+ } else { -+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); -+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; -+ err = fc0011_writereg(priv, FC11_REG_VCOSEL, -+ regs[FC11_REG_VCOSEL]); -+ if (err) -+ return err; -+ } -+ break; -+ } -+ err = fc0011_vcocal_read(priv, NULL); -+ if (err) -+ return err; -+ usleep_range(10000, 50000); -+ -+ err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]); -+ if (err) -+ return err; -+ regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE; -+ err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); -+ if (err) -+ return err; -+ err = fc0011_writereg(priv, FC11_REG_16, 0xB); -+ if (err) -+ return err; -+ -+ dev_dbg(&priv->i2c->dev, "Tuned to " -+ "fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X " -+ "vcocal=%02X(%u) bw=%u\n", -+ (unsigned int)regs[FC11_REG_FA], -+ (unsigned int)regs[FC11_REG_FP], -+ (unsigned int)regs[FC11_REG_XINHI], -+ (unsigned int)regs[FC11_REG_XINLO], -+ (unsigned int)regs[FC11_REG_VCO], -+ (unsigned int)regs[FC11_REG_VCOSEL], -+ (unsigned int)vco_cal, vco_retries, -+ (unsigned int)bandwidth); -+ -+ priv->frequency = p->frequency; -+ priv->bandwidth = p->bandwidth_hz; -+ -+ return 0; -+} -+ -+static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency) -+{ -+ struct fc0011_priv *priv = fe->tuner_priv; -+ -+ *frequency = priv->frequency; -+ -+ return 0; -+} -+ -+static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -+{ -+ *frequency = 0; -+ -+ return 0; -+} -+ -+static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -+{ -+ struct fc0011_priv *priv = fe->tuner_priv; -+ -+ *bandwidth = priv->bandwidth; -+ -+ return 0; -+} -+ -+static const struct dvb_tuner_ops fc0011_tuner_ops = { -+ .info = { -+ .name = "Fitipower FC0011", -+ -+ .frequency_min = 45000000, -+ .frequency_max = 1000000000, -+ }, -+ -+ .release = fc0011_release, -+ .init = fc0011_init, -+ -+ .set_params = fc0011_set_params, -+ -+ .get_frequency = fc0011_get_frequency, -+ .get_if_frequency = fc0011_get_if_frequency, -+ .get_bandwidth = fc0011_get_bandwidth, -+}; -+ -+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, -+ struct i2c_adapter *i2c, -+ const struct fc0011_config *config) -+{ -+ struct fc0011_priv *priv; -+ -+ priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL); -+ if (!priv) -+ return NULL; -+ -+ priv->i2c = i2c; -+ priv->addr = config->i2c_address; -+ -+ fe->tuner_priv = priv; -+ fe->ops.tuner_ops = fc0011_tuner_ops; -+ -+ dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n"); -+ -+ return fe; -+} -+EXPORT_SYMBOL(fc0011_attach); -+ -+MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); -+MODULE_AUTHOR("Michael Buesch "); -+MODULE_LICENSE("GPL"); -Index: linux-3.3.x86_64/drivers/media/common/tuners/fc0011.h -=================================================================== ---- /dev/null -+++ linux-3.3.x86_64/drivers/media/common/tuners/fc0011.h -@@ -0,0 +1,41 @@ -+#ifndef LINUX_FC0011_H_ -+#define LINUX_FC0011_H_ -+ -+#include "dvb_frontend.h" -+ -+ -+/** struct fc0011_config - fc0011 hardware config -+ * -+ * @i2c_address: I2C bus address. -+ */ -+struct fc0011_config { -+ u8 i2c_address; -+}; -+ -+/** enum fc0011_fe_callback_commands - Frontend callbacks -+ * -+ * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware. -+ * @FC0011_FE_CALLBACK_RESET: Request a tuner reset. -+ */ -+enum fc0011_fe_callback_commands { -+ FC0011_FE_CALLBACK_POWER, -+ FC0011_FE_CALLBACK_RESET, -+}; -+ -+#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\ -+ defined(CONFIG_MEDIA_TUNER_FC0011_MODULE) -+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, -+ struct i2c_adapter *i2c, -+ const struct fc0011_config *config); -+#else -+static inline -+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, -+ struct i2c_adapter *i2c, -+ const struct fc0011_config *config) -+{ -+ dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n"); -+ return NULL; -+} -+#endif -+ -+#endif /* LINUX_FC0011_H_ */ diff --git a/drm-i915-dp-stfu.patch b/drm-i915-dp-stfu.patch index 8948229dc..c005a06ba 100644 --- a/drm-i915-dp-stfu.patch +++ b/drm-i915-dp-stfu.patch @@ -1,21 +1,8 @@ -From 04a43e2598db35b3d0ec25925bb8475b5c0a3809 Mon Sep 17 00:00:00 2001 -From: Adam Jackson -Date: Fri, 16 Mar 2012 16:39:11 -0400 -Subject: [PATCH] drm/i915/dp: Use DRM_ERROR not WARN for sanity checks - -These are noisy as shit and creating a ton of abrt reports. I don't -need more, thanks. Proper fix upstream eventually. - -Signed-off-by: Adam Jackson ---- - drivers/gpu/drm/i915/intel_dp.c | 14 ++++++++------ - 1 files changed, 8 insertions(+), 6 deletions(-) - diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c -index 94f860c..6bf27c9 100644 +index 296cfc2..516e1e2 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c -@@ -331,7 +331,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) +@@ -350,7 +350,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) if (!is_edp(intel_dp)) return; if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { @@ -24,7 +11,7 @@ index 94f860c..6bf27c9 100644 DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); -@@ -386,7 +386,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, +@@ -400,7 +400,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, } if (try == 3) { @@ -33,7 +20,7 @@ index 94f860c..6bf27c9 100644 I915_READ(ch_ctl)); return -EBUSY; } -@@ -992,8 +992,8 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) +@@ -1024,8 +1024,8 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) return; DRM_DEBUG_KMS("Turn eDP VDD on\n"); @@ -44,7 +31,7 @@ index 94f860c..6bf27c9 100644 intel_dp->want_panel_vdd = true; -@@ -1058,7 +1058,8 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) +@@ -1090,7 +1090,8 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) return; DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd); @@ -54,16 +41,13 @@ index 94f860c..6bf27c9 100644 intel_dp->want_panel_vdd = false; -@@ -1128,7 +1129,8 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) +@@ -1160,7 +1161,8 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); -- WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n"); -+ if (intel_dp->want_panel_vdd) -+ DRM_ERROR("Cannot turn power off while VDD is on\n"); +- WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); ++ if (!intel_dp->want_panel_vdd) ++ DRM_ERROR("Need VDD to turn off panel\n"); pp = ironlake_get_pp_control(dev_priv); - pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); --- -1.7.7.6 - + pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); diff --git a/ext4-Support-check-none-nocheck-mount-options.patch b/ext4-Support-check-none-nocheck-mount-options.patch deleted file mode 100644 index 281e4237a..000000000 --- a/ext4-Support-check-none-nocheck-mount-options.patch +++ /dev/null @@ -1,51 +0,0 @@ -From ea75f7357e3a881bd1bd0db5e483fc6a8681567b Mon Sep 17 00:00:00 2001 -From: Josh Boyer -Date: Tue, 10 Jan 2012 09:39:02 -0500 -Subject: [PATCH] ext4: Support "check=none" "nocheck" mount options - -The ext2/ext3 filesystems supported "check=none" and "nocheck" as mount options -even though that was already the default behavior and it essentially did -nothing. When using ext4 to mount ext2/ext3 filesystems, that mount option -causes the mount to fail. That isn't as backward compatible as it could be, -so add support to ext4 to accept the option. - -Signed-off-by: Josh Boyer ---- - fs/ext4/super.c | 7 ++++++- - 1 files changed, 6 insertions(+), 1 deletions(-) - -diff --git a/fs/ext4/super.c b/fs/ext4/super.c -index 3e1329e..5ff09e7 100644 ---- a/fs/ext4/super.c -+++ b/fs/ext4/super.c -@@ -1333,7 +1333,7 @@ enum { - Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, - Opt_inode_readahead_blks, Opt_journal_ioprio, - Opt_dioread_nolock, Opt_dioread_lock, -- Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, -+ Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, Opt_nocheck, - }; - - static const match_table_t tokens = { -@@ -1409,6 +1409,8 @@ static const match_table_t tokens = { - {Opt_init_itable, "init_itable=%u"}, - {Opt_init_itable, "init_itable"}, - {Opt_noinit_itable, "noinit_itable"}, -+ {Opt_nocheck, "check=none"}, -+ {Opt_nocheck, "nocheck"}, - {Opt_err, NULL}, - }; - -@@ -1905,6 +1907,9 @@ set_qf_format: - case Opt_noinit_itable: - clear_opt(sb, INIT_INODE_TABLE); - break; -+ case Opt_nocheck: -+ /* ext2/ext3 used to "support" this option. Silently eat it */ -+ break; - default: - ext4_msg(sb, KERN_ERR, - "Unrecognized mount option \"%s\" " --- -1.7.7.5 - diff --git a/floppy-drop-disable_hlt-warning.patch b/floppy-drop-disable_hlt-warning.patch deleted file mode 100644 index 8f0849e1e..000000000 --- a/floppy-drop-disable_hlt-warning.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c -index 9955a53..aef66d1 100644 ---- a/drivers/block/floppy.c -+++ b/drivers/block/floppy.c -@@ -1038,7 +1038,7 @@ static void floppy_disable_hlt(void) - { - unsigned long flags; - -- WARN_ONCE(1, "floppy_disable_hlt() scheduled for removal in 2012"); -+ printk(KERN_INFO "floppy_disable_hlt() scheduled for removal in 2012"); - spin_lock_irqsave(&floppy_hlt_lock, flags); - if (!hlt_disabled) { - hlt_disabled = 1; diff --git a/hugetlb-fix-resv_map-leak-in-error-path.patch b/hugetlb-fix-resv_map-leak-in-error-path.patch deleted file mode 100644 index 888d5ce70..000000000 --- a/hugetlb-fix-resv_map-leak-in-error-path.patch +++ /dev/null @@ -1,176 +0,0 @@ -From c50ac050811d6485616a193eb0f37bfbd191cc89 Mon Sep 17 00:00:00 2001 -From: Dave Hansen -Date: Tue, 29 May 2012 15:06:46 -0700 -Subject: [PATCH] hugetlb: fix resv_map leak in error path - -When called for anonymous (non-shared) mappings, hugetlb_reserve_pages() -does a resv_map_alloc(). It depends on code in hugetlbfs's -vm_ops->close() to release that allocation. - -However, in the mmap() failure path, we do a plain unmap_region() without -the remove_vma() which actually calls vm_ops->close(). - -This is a decent fix. This leak could get reintroduced if new code (say, -after hugetlb_reserve_pages() in hugetlbfs_file_mmap()) decides to return -an error. But, I think it would have to unroll the reservation anyway. - -Christoph's test case: - - http://marc.info/?l=linux-mm&m=133728900729735 - -This patch applies to 3.4 and later. A version for earlier kernels is at -https://lkml.org/lkml/2012/5/22/418. - -Signed-off-by: Dave Hansen -Acked-by: Mel Gorman -Acked-by: KOSAKI Motohiro -Reported-by: Christoph Lameter -Tested-by: Christoph Lameter -Cc: Andrea Arcangeli -Cc: [2.6.32+] -Signed-off-by: Andrew Morton -Signed-off-by: Linus Torvalds ---- - mm/hugetlb.c | 28 ++++++++++++++++++++++------ - 1 files changed, 22 insertions(+), 6 deletions(-) - -diff --git a/mm/hugetlb.c b/mm/hugetlb.c -index 41a647d..285a81e 100644 ---- a/mm/hugetlb.c -+++ b/mm/hugetlb.c -@@ -2157,6 +2157,15 @@ static void hugetlb_vm_op_open(struct vm_area_struct *vma) - kref_get(&reservations->refs); - } - -+static void resv_map_put(struct vm_area_struct *vma) -+{ -+ struct resv_map *reservations = vma_resv_map(vma); -+ -+ if (!reservations) -+ return; -+ kref_put(&reservations->refs, resv_map_release); -+} -+ - static void hugetlb_vm_op_close(struct vm_area_struct *vma) - { - struct hstate *h = hstate_vma(vma); -@@ -2173,7 +2182,7 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma) - reserve = (end - start) - - region_count(&reservations->regions, start, end); - -- kref_put(&reservations->refs, resv_map_release); -+ resv_map_put(vma); - - if (reserve) { - hugetlb_acct_memory(h, -reserve); -@@ -2991,12 +3000,16 @@ int hugetlb_reserve_pages(struct inode *inode, - set_vma_resv_flags(vma, HPAGE_RESV_OWNER); - } - -- if (chg < 0) -- return chg; -+ if (chg < 0) { -+ ret = chg; -+ goto out_err; -+ } - - /* There must be enough pages in the subpool for the mapping */ -- if (hugepage_subpool_get_pages(spool, chg)) -- return -ENOSPC; -+ if (hugepage_subpool_get_pages(spool, chg)) { -+ ret = -ENOSPC; -+ goto out_err; -+ } - - /* - * Check enough hugepages are available for the reservation. -@@ -3005,7 +3018,7 @@ int hugetlb_reserve_pages(struct inode *inode, - ret = hugetlb_acct_memory(h, chg); - if (ret < 0) { - hugepage_subpool_put_pages(spool, chg); -- return ret; -+ goto out_err; - } - - /* -@@ -3022,6 +3035,9 @@ int hugetlb_reserve_pages(struct inode *inode, - if (!vma || vma->vm_flags & VM_MAYSHARE) - region_add(&inode->i_mapping->private_list, from, to); - return 0; -+out_err: -+ resv_map_put(vma); -+ return ret; - } - - void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) --- -1.7.7.6 - -From 4523e1458566a0e8ecfaff90f380dd23acc44d27 Mon Sep 17 00:00:00 2001 -From: Dave Hansen -Date: Wed, 30 May 2012 07:51:07 -0700 -Subject: [PATCH] mm: fix vma_resv_map() NULL pointer - -hugetlb_reserve_pages() can be used for either normal file-backed -hugetlbfs mappings, or MAP_HUGETLB. In the MAP_HUGETLB, semi-anonymous -mode, there is not a VMA around. The new call to resv_map_put() assumed -that there was, and resulted in a NULL pointer dereference: - - BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 - IP: vma_resv_map+0x9/0x30 - PGD 141453067 PUD 1421e1067 PMD 0 - Oops: 0000 [#1] PREEMPT SMP - ... - Pid: 14006, comm: trinity-child6 Not tainted 3.4.0+ #36 - RIP: vma_resv_map+0x9/0x30 - ... - Process trinity-child6 (pid: 14006, threadinfo ffff8801414e0000, task ffff8801414f26b0) - Call Trace: - resv_map_put+0xe/0x40 - hugetlb_reserve_pages+0xa6/0x1d0 - hugetlb_file_setup+0x102/0x2c0 - newseg+0x115/0x360 - ipcget+0x1ce/0x310 - sys_shmget+0x5a/0x60 - system_call_fastpath+0x16/0x1b - -This was reported by Dave Jones, but was reproducible with the -libhugetlbfs test cases, so shame on me for not running them in the -first place. - -With this, the oops is gone, and the output of libhugetlbfs's -run_tests.py is identical to plain 3.4 again. - -[ Marked for stable, since this was introduced by commit c50ac050811d - ("hugetlb: fix resv_map leak in error path") which was also marked for - stable ] - -Reported-by: Dave Jones -Cc: Mel Gorman -Cc: KOSAKI Motohiro -Cc: Christoph Lameter -Cc: Andrea Arcangeli -Cc: Andrew Morton -Cc: [2.6.32+] -Signed-off-by: Linus Torvalds ---- - mm/hugetlb.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/mm/hugetlb.c b/mm/hugetlb.c -index 285a81e..e198831 100644 ---- a/mm/hugetlb.c -+++ b/mm/hugetlb.c -@@ -3036,7 +3036,8 @@ int hugetlb_reserve_pages(struct inode *inode, - region_add(&inode->i_mapping->private_list, from, to); - return 0; - out_err: -- resv_map_put(vma); -+ if (vma) -+ resv_map_put(vma); - return ret; - } - --- -1.7.7.6 - diff --git a/iwlwifi-disable-the-buggy-chain-extension-feature-in-HW.patch b/iwlwifi-disable-the-buggy-chain-extension-feature-in-HW.patch new file mode 100644 index 000000000..c4f2ed3a1 --- /dev/null +++ b/iwlwifi-disable-the-buggy-chain-extension-feature-in-HW.patch @@ -0,0 +1,48 @@ +From d012d04e4d6312ea157b6cf19e9689af934f5aa7 Mon Sep 17 00:00:00 2001 +From: Emmanuel Grumbach +Date: Wed, 6 Jun 2012 13:55:02 +0200 +Subject: [PATCH] iwlwifi: disable the buggy chain extension feature in HW + +This feature has been reported to be buggy and enabled by +default. We therefore need to disable it manually. + +Cc: stable@vger.kernel.org +Signed-off-by: Emmanuel Grumbach +Signed-off-by: Johannes Berg +Signed-off-by: John W. Linville +--- + drivers/net/wireless/iwlwifi/iwl-prph.h | 1 + + drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 5 +++++ + 2 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h +index 3b10692..dfd5466 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-prph.h ++++ b/drivers/net/wireless/iwlwifi/iwl-prph.h +@@ -224,6 +224,7 @@ + #define SCD_TXFACT (SCD_BASE + 0x10) + #define SCD_ACTIVE (SCD_BASE + 0x14) + #define SCD_QUEUECHAIN_SEL (SCD_BASE + 0xe8) ++#define SCD_CHAINEXT_EN (SCD_BASE + 0x244) + #define SCD_AGGR_SEL (SCD_BASE + 0x248) + #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) + +diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +index ec6fb39..79c6b91 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c ++++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +@@ -1058,6 +1058,11 @@ static void iwl_tx_start(struct iwl_trans *trans) + iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, + trans_pcie->scd_bc_tbls.dma >> 10); + ++ /* The chain extension of the SCD doesn't work well. This feature is ++ * enabled by default by the HW, so we need to disable it manually. ++ */ ++ iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); ++ + /* Enable DMA channel */ + for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++) + iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan), +-- +1.7.7.6 + diff --git a/iwlwifi-dont-mess-up-the-SCD-when-removing-a-key.patch b/iwlwifi-dont-mess-up-the-SCD-when-removing-a-key.patch new file mode 100644 index 000000000..f7c3c7181 --- /dev/null +++ b/iwlwifi-dont-mess-up-the-SCD-when-removing-a-key.patch @@ -0,0 +1,45 @@ +From d6ee27eb13beab94056e0de52d81220058ca2297 Mon Sep 17 00:00:00 2001 +From: Emmanuel Grumbach +Date: Wed, 6 Jun 2012 09:13:36 +0200 +Subject: [PATCH] iwlwifi: don't mess up the SCD when removing a key + +When we remove a key, we put a key index which was supposed +to tell the fw that we are actually removing the key. But +instead the fw took that index as a valid index and messed +up the SRAM of the device. + +This memory corruption on the device mangled the data of +the SCD. The impact on the user is that SCD queue 2 got +stuck after having removed keys. +The message is the log that was printed is: + +Queue 2 stuck for 10000ms + +This doesn't seem to fix the higher queues that get stuck +from time to time. + +Cc: stable@vger.kernel.org [2.6.27+] +Reviewed-by: Meenakshi Venkataraman +Signed-off-by: Emmanuel Grumbach +Signed-off-by: Johannes Berg +Signed-off-by: John W. Linville +--- + drivers/net/wireless/iwlwifi/iwl-agn-sta.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +index aea07aa..eb6a8ea 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c ++++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +@@ -1267,7 +1267,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, + key_flags |= STA_KEY_MULTICAST_MSK; + + sta_cmd.key.key_flags = key_flags; +- sta_cmd.key.key_offset = WEP_INVALID_OFFSET; ++ sta_cmd.key.key_offset = keyconf->hw_key_idx; + sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK; + sta_cmd.mode = STA_CONTROL_MODIFY_MSK; + +-- +1.7.6.5 + diff --git a/kernel.spec b/kernel.spec index 7a442ed55..068ded8b9 100644 --- a/kernel.spec +++ b/kernel.spec @@ -60,13 +60,13 @@ Summary: The Linux kernel # base_sublevel is the kernel version we're starting with and patching # on top of -- for example, 2.6.22-rc7-git1 starts with a 2.6.21 base, # which yields a base_sublevel of 21. -%define base_sublevel 3 +%define base_sublevel 4 ## If this is a released kernel ## %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 8 +%define stable_update 2 # Is it a -stable RC? %define stable_rc 0 # Set rpm version accordingly @@ -409,12 +409,13 @@ Summary: The Linux kernel # we build a up kernel on armv5tel. its used for qemu. %ifnarch armv5tel %define with_up 0 -%define with_perf 0 %endif # we only build headers on the base arm arches # just like we used to only build them on i386 for x86 %ifnarch armv5tel armv7hl %define with_headers 0 +%define with_perf 0 +%define with_tools 0 %endif %endif @@ -661,8 +662,6 @@ Patch160: linux-2.6-32bit-mmap-exec-randomization.patch Patch161: linux-2.6-i386-nx-emulation.patch Patch162: nx-emu-remove-cpuinitdata-for-disable_nx-on-x86_32.patch -Patch383: linux-2.6-defaults-aspm.patch - Patch390: linux-2.6-defaults-acpi-video.patch Patch391: linux-2.6-acpi-video-dos.patch Patch394: linux-2.6-acpi-debug-infinite-loop.patch @@ -674,10 +673,8 @@ Patch452: linux-2.6.30-no-pcspkr-modalias.patch Patch460: linux-2.6-serial-460800.patch Patch470: die-floppy-die.patch -Patch471: floppy-drop-disable_hlt-warning.patch Patch510: linux-2.6-silence-noise.patch -Patch511: silence-timekeeping-spew.patch Patch520: quite-apm.patch Patch530: linux-2.6-silence-fbcon-logo.patch @@ -707,8 +704,6 @@ Patch1900: linux-2.6-intel-iommu-igfx.patch Patch2802: linux-2.6-silence-acpi-blacklist.patch # media patches -# add-poll-requested-events.patch was added for 3.4 -Patch2900: add-poll-requested-events.patch Patch2901: drivers-media-update.patch # fs fixes @@ -717,14 +712,6 @@ Patch2901: drivers-media-update.patch Patch3500: jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch # NFSv4 -Patch4000: NFSv4-Reduce-the-footprint-of-the-idmapper.patch -Patch4001: NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch -Patch4107: NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch - -# NFS Client Patch set from Upstream -Patch4113: NFS-optimise-away-unnecessary-setattrs-for-open-O_TRUNC.patch -Patch4114: NFSv4-fix-open-O_TRUNC-and-ftruncate-error-handling.patch -Patch4115: NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch # patches headed upstream @@ -736,48 +723,25 @@ Patch13003: efi-dont-map-boot-services-on-32bit.patch Patch14010: lis3-improve-handling-of-null-rate.patch -Patch15000: bluetooth-use-after-free.patch - Patch19000: ips-noirq.patch -Patch20000: utrace.patch - # Flattened devicetree support Patch21000: arm-omap-dt-compat.patch Patch21001: arm-smsc-support-reading-mac-address-from-device-tree.patch -Patch21070: ext4-Support-check-none-nocheck-mount-options.patch - #rhbz 769766 Patch21072: mac80211-fix-rx-key-NULL-ptr-deref-in-promiscuous-mode.patch Patch21226: pci-crs-blacklist.patch -#rhbz 772772 -Patch21232: rt2x00_fix_MCU_request_failures.patch - #rhbz 754518 #Patch21235: scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch -#rhbz 789644 -Patch21237: mcelog-rcu-splat.patch - Patch21300: unhandled-irqs-switch-to-polling.patch #rhbz 804957 CVE-2012-1568 Patch21306: shlib_base_randomize.patch -#rhbz 804347 -Patch21351: x86-add-io_apic_ops-to-allow-interception.patch -Patch21352: x86-apic_ops-Replace-apic_ops-with-x86_apic_ops.patch -Patch21353: xen-x86-Implement-x86_apic_ops.patch - -#rhbz 808559 -Patch21530: ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch - -#rhbz 806295 -Patch21710: disable-hid-battery.patch - # Debug patches Patch30000: weird-root-dentry-name-debug.patch Patch30010: debug-808990.patch @@ -789,7 +753,7 @@ Patch22007: macvtap-zerocopy-validate-vector-length.patch Patch22013: ipw2x00-add-supported-cipher-suites-to-wiphy-initialization.patch #rhbz 749276 -Patch22018: atl1c_net_next_update-3.3.patch +Patch22018: atl1c_net_next_update-3.4.patch #rhbz 795176 Patch22019: rtl818x-fix-sleeping-function-called-from-invalid-context.patch @@ -797,8 +761,16 @@ Patch22019: rtl818x-fix-sleeping-function-called-from-invalid-context.patch #rhbz 822825 822821 CVE-2012-2372 Patch22021: mm-pmd_read_atomic-fix-32bit-PAE-pmd-walk-vs-pmd_populate-SMP-race-condition.patch -#rhbz 824352 824345 CVE-2012-2390 -Patch22022: hugetlb-fix-resv_map-leak-in-error-path.patch +#rhbz 829016 +Patch22022: thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch + +#rhbz 825491 +Patch22023: iwlwifi-disable-the-buggy-chain-extension-feature-in-HW.patch +Patch22024: iwlwifi-dont-mess-up-the-SCD-when-removing-a-key.patch + +#rhbz 830862 +Patch22030: SUNRPC-new-svc_bind-routine-introduced.patch +Patch22031: SUNRPC-move-per-net-operations-from-svc_destroy.patch # END OF PATCH DEFINITIONS @@ -1304,7 +1276,7 @@ ApplyOptionalPatch linux-2.6-upstream-reverts.patch -R # ARM # # ApplyPatch arm-omap-dt-compat.patch -ApplyPatch arm-smsc-support-reading-mac-address-from-device-tree.patch +# ApplyPatch arm-smsc-support-reading-mac-address-from-device-tree.patch ApplyPatch taint-vbox.patch # @@ -1333,14 +1305,6 @@ ApplyPatch jbd-jbd2-validate-sb-s_first-in-journal_get_superblo.patch # eCryptfs # NFSv4 -ApplyPatch NFSv4-Reduce-the-footprint-of-the-idmapper.patch -ApplyPatch NFSv4-Further-reduce-the-footprint-of-the-idmapper.patch -ApplyPatch NFSv4-Minor-cleanups-for-nfs4_handle_exception-and-n.patch - -# NFS Client Patch set from Upstream -ApplyPatch NFS-optimise-away-unnecessary-setattrs-for-open-O_TRUNC.patch -ApplyPatch NFSv4-fix-open-O_TRUNC-and-ftruncate-error-handling.patch -ApplyPatch NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch # USB @@ -1355,8 +1319,6 @@ ApplyPatch acpi-sony-nonvs-blacklist.patch # # PCI # -# enable ASPM by default on hardware we expect to work -ApplyPatch linux-2.6-defaults-aspm.patch # # SCSI Bits. @@ -1366,9 +1328,6 @@ ApplyPatch linux-2.6-defaults-aspm.patch # ALSA -#rhbz 808559 -ApplyPatch ALSA-hda-realtek-Add-quirk-for-Mac-Pro-5-1-machines.patch - # Networking @@ -1378,7 +1337,6 @@ ApplyPatch linux-2.6-input-kill-stupid-messages.patch # stop floppy.ko from autoloading during udev... ApplyPatch die-floppy-die.patch -ApplyPatch floppy-drop-disable_hlt-warning.patch ApplyPatch linux-2.6.30-no-pcspkr-modalias.patch @@ -1388,8 +1346,6 @@ ApplyPatch linux-2.6-serial-460800.patch # Silence some useless messages that still get printed with 'quiet' ApplyPatch linux-2.6-silence-noise.patch -ApplyPatch silence-timekeeping-spew.patch - # Make fbcon not show the penguins with 'quiet' ApplyPatch linux-2.6-silence-fbcon-logo.patch @@ -1423,7 +1379,6 @@ ApplyPatch quite-apm.patch # Media (V4L/DVB/IR) updates/fixes/experimental drivers # apply if non-empty -ApplyPatch add-poll-requested-events.patch ApplyOptionalPatch drivers-media-update.patch # Patches headed upstream @@ -1437,40 +1392,19 @@ ApplyPatch efi-dont-map-boot-services-on-32bit.patch ApplyPatch lis3-improve-handling-of-null-rate.patch -ApplyPatch bluetooth-use-after-free.patch - ApplyPatch ips-noirq.patch -# utrace. -ApplyPatch utrace.patch - #ApplyPatch pci-crs-blacklist.patch -ApplyPatch ext4-Support-check-none-nocheck-mount-options.patch - -#rhbz 772772 -ApplyPatch rt2x00_fix_MCU_request_failures.patch - #rhbz 754518 #ApplyPatch scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch -#rhbz 789644 -ApplyPatch mcelog-rcu-splat.patch - ApplyPatch unhandled-irqs-switch-to-polling.patch # debug patches ApplyPatch weird-root-dentry-name-debug.patch ApplyPatch debug-808990.patch -#rhbz 804347 -ApplyPatch x86-add-io_apic_ops-to-allow-interception.patch -ApplyPatch x86-apic_ops-Replace-apic_ops-with-x86_apic_ops.patch -ApplyPatch xen-x86-Implement-x86_apic_ops.patch - -#rhbz 806295 -ApplyPatch disable-hid-battery.patch - #rhbz 814278 814289 CVE-2012-2119 ApplyPatch macvtap-zerocopy-validate-vector-length.patch @@ -1478,7 +1412,7 @@ ApplyPatch macvtap-zerocopy-validate-vector-length.patch ApplyPatch ipw2x00-add-supported-cipher-suites-to-wiphy-initialization.patch #rhbz 749276 -ApplyPatch atl1c_net_next_update-3.3.patch +ApplyPatch atl1c_net_next_update-3.4.patch #rhbz 795176 ApplyPatch rtl818x-fix-sleeping-function-called-from-invalid-context.patch @@ -1486,8 +1420,15 @@ ApplyPatch rtl818x-fix-sleeping-function-called-from-invalid-context.patch #rhbz 822825 822821 CVE-2012-2372 ApplyPatch mm-pmd_read_atomic-fix-32bit-PAE-pmd-walk-vs-pmd_populate-SMP-race-condition.patch -#rhbz 824352 824345 CVE-2012-2390 -ApplyPatch hugetlb-fix-resv_map-leak-in-error-path.patch +ApplyPatch thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch + +#rhbz 825491 +ApplyPatch iwlwifi-disable-the-buggy-chain-extension-feature-in-HW.patch +ApplyPatch iwlwifi-dont-mess-up-the-SCD-when-removing-a-key.patch + +#rhbz 830862 +ApplyPatch SUNRPC-new-svc_bind-routine-introduced.patch +ApplyPatch SUNRPC-move-per-net-operations-from-svc_destroy.patch # END OF PATCH APPLICATIONS @@ -2227,6 +2168,9 @@ fi # and build. %changelog +* Thu Jun 14 2012 Justin M. Forbes 3.4.2-1 +- Linux 3.4.2 + * Mon Jun 04 2012 Josh Boyer 3.3.8-1 - Linux v3.3.8 diff --git a/linux-2.6-acpi-debug-infinite-loop.patch b/linux-2.6-acpi-debug-infinite-loop.patch index d20025224..f2cc1a55e 100644 --- a/linux-2.6-acpi-debug-infinite-loop.patch +++ b/linux-2.6-acpi-debug-infinite-loop.patch @@ -1,5 +1,5 @@ ---- linux-2.6.34.noarch/drivers/acpi/acpica/acconfig.h~ 2010-07-01 14:49:03.000000000 -0400 -+++ linux-2.6.34.noarch/drivers/acpi/acpica/acconfig.h 2010-07-01 14:49:17.000000000 -0400 +--- linux-2.6.34.noarch/include/acpi/acconfig.h~ 2010-07-01 14:49:03.000000000 -0400 ++++ linux-2.6.34.noarch/include/acpi/acconfig.h 2010-07-01 14:49:17.000000000 -0400 @@ -117,7 +117,7 @@ /* Maximum number of While() loop iterations before forced abort */ diff --git a/linux-2.6-defaults-aspm.patch b/linux-2.6-defaults-aspm.patch deleted file mode 100644 index 49b832d2c..000000000 --- a/linux-2.6-defaults-aspm.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up linux-2.6.30.noarch/drivers/pci/pcie/aspm.c.mjg linux-2.6.30.noarch/drivers/pci/pcie/aspm.c ---- linux-2.6.30.noarch/drivers/pci/pcie/aspm.c.mjg 2009-07-16 22:01:11.000000000 +0100 -+++ linux-2.6.30.noarch/drivers/pci/pcie/aspm.c 2009-07-16 22:01:30.000000000 +0100 -@@ -65,7 +65,7 @@ static LIST_HEAD(link_list); - #define POLICY_DEFAULT 0 /* BIOS default setting */ - #define POLICY_PERFORMANCE 1 /* high performance */ - #define POLICY_POWERSAVE 2 /* high power saving */ --static int aspm_policy; -+static int aspm_policy = POLICY_POWERSAVE; - static const char *policy_str[] = { - [POLICY_DEFAULT] = "default", - [POLICY_PERFORMANCE] = "performance", diff --git a/mcelog-rcu-splat.patch b/mcelog-rcu-splat.patch deleted file mode 100644 index 12c1fe3ea..000000000 --- a/mcelog-rcu-splat.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c -index f22a9f7..f525f99 100644 ---- a/arch/x86/kernel/cpu/mcheck/mce.c -+++ b/arch/x86/kernel/cpu/mcheck/mce.c -@@ -191,7 +191,7 @@ static void drain_mcelog_buffer(void) - { - unsigned int next, i, prev = 0; - -- next = rcu_dereference_check_mce(mcelog.next); -+ next = ACCESS_ONCE(mcelog.next); - - do { - struct mce *m; - - \ No newline at end of file diff --git a/rt2x00_fix_MCU_request_failures.patch b/rt2x00_fix_MCU_request_failures.patch deleted file mode 100644 index f7b8a6a4c..000000000 --- a/rt2x00_fix_MCU_request_failures.patch +++ /dev/null @@ -1,136 +0,0 @@ -diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h -index 2571a2f..822f9e5 100644 ---- a/drivers/net/wireless/rt2x00/rt2800.h -+++ b/drivers/net/wireless/rt2x00/rt2800.h -@@ -1627,6 +1627,7 @@ struct mac_iveiv_entry { - - /* - * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. -+ * CMD_TOKEN: Command id, 0xff disable status reporting - */ - #define H2M_MAILBOX_CSR 0x7010 - #define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) -@@ -1636,6 +1637,8 @@ struct mac_iveiv_entry { - - /* - * H2M_MAILBOX_CID: -+ * Free slots contain 0xff. MCU will store command's token to lowest free slot. -+ * If all slots are occupied status will be dropped. - */ - #define H2M_MAILBOX_CID 0x7014 - #define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) -@@ -1645,6 +1648,7 @@ struct mac_iveiv_entry { - - /* - * H2M_MAILBOX_STATUS: -+ * Command status will be saved to same slot as command id. - */ - #define H2M_MAILBOX_STATUS 0x701c - -@@ -2259,6 +2263,12 @@ struct mac_iveiv_entry { - - /* - * MCU mailbox commands. -+ * MCU_SLEEP - go to power-save mode. -+ * arg1: 1: save as much power as possible, 0: save less power -+ * status: 1: success, 2: already asleep, -+ * 3: maybe MAC is busy so can't finish this task -+ * MCU_RADIO_OFF -+ * arg0: 0: do power-saving, NOT turn off radio - */ - #define MCU_SLEEP 0x30 - #define MCU_WAKEUP 0x31 -@@ -2279,7 +2289,9 @@ struct mac_iveiv_entry { - /* - * MCU mailbox tokens - */ --#define TOKEN_WAKUP 3 -+#define TOKEN_SLEEP 1 -+#define TOKEN_RADIO_OFF 2 -+#define TOKEN_WAKEUP 3 - - /* - * DMA descriptor defines. -diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c -index dc88bae..9ac3017 100644 ---- a/drivers/net/wireless/rt2x00/rt2800pci.c -+++ b/drivers/net/wireless/rt2x00/rt2800pci.c -@@ -517,23 +517,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) - } - } - --static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, -- enum dev_state state) --{ -- if (state == STATE_AWAKE) { -- rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02); -- rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); -- } else if (state == STATE_SLEEP) { -- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, -- 0xffffffff); -- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, -- 0xffffffff); -- rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01); -- } -- -- return 0; --} -- - static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, - enum dev_state state) - { -@@ -541,14 +524,20 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, - - switch (state) { - case STATE_RADIO_ON: -- /* -- * Before the radio can be enabled, the device first has -- * to be woken up. After that it needs a bit of time -- * to be fully awake and then the radio can be enabled. -- */ -- rt2800pci_set_state(rt2x00dev, STATE_AWAKE); -- msleep(1); -+ /* Initialise all registers and send MCU_BOOT_SIGNAL. */ - retval = rt2800pci_enable_radio(rt2x00dev); -+ -+ /* After resume MCU_BOOT_SIGNAL will trash those. */ -+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); -+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); -+ -+ /* Finish initialization procedure. */ -+ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, -+ 0xff, 0x02); -+ rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF); -+ -+ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, 0, 0); -+ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP); - break; - case STATE_RADIO_OFF: - /* -@@ -556,7 +545,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, - * be put to sleep for powersaving. - */ - rt2800pci_disable_radio(rt2x00dev); -- rt2800pci_set_state(rt2x00dev, STATE_SLEEP); -+ rt2800pci_set_device_state(rt2x00dev, STATE_SLEEP); - break; - case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_OFF: -@@ -565,8 +554,16 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, - case STATE_DEEP_SLEEP: - case STATE_SLEEP: - case STATE_STANDBY: -+ /* PCIe devices won't report status after SLEEP request. */ -+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); -+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); -+ rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP, -+ 0xff, 0x01); -+ break; - case STATE_AWAKE: -- retval = rt2800pci_set_state(rt2x00dev, state); -+ rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKEUP, -+ 0, 0x02); -+ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP); - break; - default: - retval = -ENOTSUPP; diff --git a/silence-timekeeping-spew.patch b/silence-timekeeping-spew.patch deleted file mode 100644 index 19416d433..000000000 --- a/silence-timekeeping-spew.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- linux-3.3.0-4.fc17.noarch/kernel/time/timekeeping.c~ 2012-03-30 14:18:15.591162207 -0400 -+++ linux-3.3.0-4.fc17.noarch/kernel/time/timekeeping.c 2012-03-30 14:18:38.959121171 -0400 -@@ -854,13 +854,6 @@ static void timekeeping_adjust(s64 offse - } else /* No adjustment needed */ - return; - -- WARN_ONCE(timekeeper.clock->maxadj && -- (timekeeper.mult + adj > timekeeper.clock->mult + -- timekeeper.clock->maxadj), -- "Adjusting %s more then 11%% (%ld vs %ld)\n", -- timekeeper.clock->name, (long)timekeeper.mult + adj, -- (long)timekeeper.clock->mult + -- timekeeper.clock->maxadj); - /* - * So the following can be confusing. - * diff --git a/sources b/sources index 033ae54df..cd364717e 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -7133f5a2086a7d7ef97abac610c094f5 linux-3.3.tar.xz -e1714b5136a7f4dab1b5d2d7f98e2891 patch-3.3.8.xz +967f72983655e2479f951195953e8480 linux-3.4.tar.xz +ac52d3d82c20c7e80740fc5fb00b6ed4 patch-3.4.2.xz diff --git a/thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch b/thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch new file mode 100644 index 000000000..a91e9bbe4 --- /dev/null +++ b/thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-PAE.patch @@ -0,0 +1,228 @@ + +Delivered-To: jwboyer@gmail.com +Received: by 10.229.175.203 with SMTP id bb11csp66243qcb; + Fri, 8 Jun 2012 15:08:27 -0700 (PDT) +Received: by 10.68.222.133 with SMTP id qm5mr23412736pbc.113.1339193307132; + Fri, 08 Jun 2012 15:08:27 -0700 (PDT) +Return-Path: +Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) + by mx.google.com with ESMTP id ku9si12482578pbc.355.2012.06.08.15.08.24; + Fri, 08 Jun 2012 15:08:25 -0700 (PDT) +Received-SPF: pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; +Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mail=stable-owner@vger.kernel.org +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S964992Ab2FHWIW (ORCPT + 21 others); + Fri, 8 Jun 2012 18:08:22 -0400 +Received: from mail-bk0-f74.google.com ([209.85.214.74]:41783 "EHLO + mail-bk0-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S964922Ab2FHWIV (ORCPT + ); Fri, 8 Jun 2012 18:08:21 -0400 +Received: by bkty5 with SMTP id y5so128736bkt.1 + for ; Fri, 08 Jun 2012 15:08:20 -0700 (PDT) +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=google.com; s=20120113; + h=subject:to:cc:from:date:message-id:x-gm-message-state; + bh=RSdNZSZcXg/enKaYIM+JR4+Bd890ieO+blY9bsk9giI=; + b=NwTZEmRSdqDAiTV/EW91GXpM/yrRd7CNzfPif0JcF0iFgxGAo4lB7W1I05vmrnPcCQ + Va+P6xXLWle2rAVQLsPooKdtb3u2wnNRDEGvBPZl2alje+qzhKGlQcVgnI5+KCM6GaS+ + YWoE+2gv5UFmF6JlelThyecGTyZ0D93K5aVYewSxg0H7KZ6BgvMnB/qJKFdScatv1uDH + g39MFwJzmD+DmNMn149jeUWYOLLTeMZJkymtJCLgxS8eJzQxXA0nes2Wz/pXCBdxXF2z + mft6LyzKtoEUDeTtalgm9zxkT4XJ+6bsAMEXBFgkcyNq0Ic8P79AP0ynlET2L/Ql3ARP + C5Sg== +Received: by 10.14.101.2 with SMTP id a2mr2823176eeg.6.1339193299969; + Fri, 08 Jun 2012 15:08:19 -0700 (PDT) +Received: from hpza10.eem.corp.google.com ([74.125.121.33]) + by gmr-mx.google.com with ESMTPS id d52si7345113eei.1.2012.06.08.15.08.19 + (version=TLSv1/SSLv3 cipher=AES128-SHA); + Fri, 08 Jun 2012 15:08:19 -0700 (PDT) +Received: from akpm.mtv.corp.google.com (akpm.mtv.corp.google.com [172.18.96.75]) + by hpza10.eem.corp.google.com (Postfix) with ESMTP id 9D09620004E; + Fri, 8 Jun 2012 15:08:19 -0700 (PDT) +Received: from localhost.localdomain (localhost [127.0.0.1]) + by akpm.mtv.corp.google.com (Postfix) with ESMTP id D5FACA0329; + Fri, 8 Jun 2012 15:08:18 -0700 (PDT) +Subject: + thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae.patch added to -mm tree +To: mm-commits@vger.kernel.org +Cc: aarcange@redhat.com, hughd@google.com, jbeulich@suse.com, + jrnieder@gmail.com, kosaki.motohiro@gmail.com, lwoodman@redhat.com, + mgorman@suse.de, pmatouse@redhat.com, riel@redhat.com, + stable@vger.kernel.org, uobergfe@redhat.com +From: akpm@linux-foundation.org +Date: Fri, 08 Jun 2012 15:08:18 -0700 +Message-Id: <20120608220818.D5FACA0329@akpm.mtv.corp.google.com> +X-Gm-Message-State: ALoCoQnqC0C+2OVVfC5Yi43jUu5vH03b/RBncPoI4SpE4HFSgaRrM+gM2J8rR6MMoba3nM/OmDAU +Sender: stable-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: stable@vger.kernel.org + + +The patch titled + Subject: thp: avoid atomic64_read in pmd_read_atomic for 32bit PAE +has been added to the -mm tree. Its filename is + thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae.patch + +Before you just go and hit "reply", please: + a) Consider who else should be cc'ed + b) Prefer to cc a suitable mailing list as well + c) Ideally: find the original patch on the mailing list and do a + reply-to-all to that, adding suitable additional cc's + +*** Remember to use Documentation/SubmitChecklist when testing your code *** + +The -mm tree is included into linux-next and is updated +there every 3-4 working days + +------------------------------------------------------ +From: Andrea Arcangeli +Subject: thp: avoid atomic64_read in pmd_read_atomic for 32bit PAE + +In the x86 32bit PAE CONFIG_TRANSPARENT_HUGEPAGE=y case while holding the +mmap_sem for reading, cmpxchg8b cannot be used to read pmd contents under +Xen. + +So instead of dealing only with "consistent" pmdvals in +pmd_none_or_trans_huge_or_clear_bad() (which would be conceptually +simpler) we let pmd_none_or_trans_huge_or_clear_bad() deal with pmdvals +where the low 32bit and high 32bit could be inconsistent (to avoid having +to use cmpxchg8b). + +The only guarantee we get from pmd_read_atomic is that if the low part of +the pmd was found null, the high part will be null too (so the pmd will be +considered unstable). And if the low part of the pmd is found "stable" +later, then it means the whole pmd was read atomically (because after a +pmd is stable, neither MADV_DONTNEED nor page faults can alter it anymore, +and we read the high part after the low part). + +In the 32bit PAE x86 case, it is enough to read the low part of the pmdval +atomically to declare the pmd as "stable" and that's true for THP and no +THP, furthermore in the THP case we also have a barrier() that will +prevent any inconsistent pmdvals to be cached by a later re-read of the +*pmd. + +Signed-off-by: Andrea Arcangeli +Cc: Jonathan Nieder +Cc: Ulrich Obergfell +Cc: Mel Gorman +Cc: Hugh Dickins +Cc: Larry Woodman +Cc: Petr Matousek +Cc: Rik van Riel +Cc: Jan Beulich +Cc: KOSAKI Motohiro +Cc: +Signed-off-by: Andrew Morton +--- + + arch/x86/include/asm/pgtable-3level.h | 30 +++++++++++++----------- + include/asm-generic/pgtable.h | 10 ++++++++ + 2 files changed, 27 insertions(+), 13 deletions(-) + +diff -puN arch/x86/include/asm/pgtable-3level.h~thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae arch/x86/include/asm/pgtable-3level.h +--- a/arch/x86/include/asm/pgtable-3level.h~thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae ++++ a/arch/x86/include/asm/pgtable-3level.h +@@ -47,16 +47,26 @@ static inline void native_set_pte(pte_t + * they can run pmd_offset_map_lock or pmd_trans_huge or other pmd + * operations. + * +- * Without THP if the mmap_sem is hold for reading, the +- * pmd can only transition from null to not null while pmd_read_atomic runs. +- * So there's no need of literally reading it atomically. ++ * Without THP if the mmap_sem is hold for reading, the pmd can only ++ * transition from null to not null while pmd_read_atomic runs. So ++ * we can always return atomic pmd values with this function. + * + * With THP if the mmap_sem is hold for reading, the pmd can become +- * THP or null or point to a pte (and in turn become "stable") at any +- * time under pmd_read_atomic, so it's mandatory to read it atomically +- * with cmpxchg8b. ++ * trans_huge or none or point to a pte (and in turn become "stable") ++ * at any time under pmd_read_atomic. We could read it really ++ * atomically here with a atomic64_read for the THP enabled case (and ++ * it would be a whole lot simpler), but to avoid using cmpxchg8b we ++ * only return an atomic pmdval if the low part of the pmdval is later ++ * found stable (i.e. pointing to a pte). And we're returning a none ++ * pmdval if the low part of the pmd is none. In some cases the high ++ * and low part of the pmdval returned may not be consistent if THP is ++ * enabled (the low part may point to previously mapped hugepage, ++ * while the high part may point to a more recently mapped hugepage), ++ * but pmd_none_or_trans_huge_or_clear_bad() only needs the low part ++ * of the pmd to be read atomically to decide if the pmd is unstable ++ * or not, with the only exception of when the low part of the pmd is ++ * zero in which case we return a none pmd. + */ +-#ifndef CONFIG_TRANSPARENT_HUGEPAGE + static inline pmd_t pmd_read_atomic(pmd_t *pmdp) + { + pmdval_t ret; +@@ -74,12 +84,6 @@ static inline pmd_t pmd_read_atomic(pmd_ + + return (pmd_t) { ret }; + } +-#else /* CONFIG_TRANSPARENT_HUGEPAGE */ +-static inline pmd_t pmd_read_atomic(pmd_t *pmdp) +-{ +- return (pmd_t) { atomic64_read((atomic64_t *)pmdp) }; +-} +-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + + static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) + { +diff -puN include/asm-generic/pgtable.h~thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae include/asm-generic/pgtable.h +--- a/include/asm-generic/pgtable.h~thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae ++++ a/include/asm-generic/pgtable.h +@@ -484,6 +484,16 @@ static inline int pmd_none_or_trans_huge + /* + * The barrier will stabilize the pmdval in a register or on + * the stack so that it will stop changing under the code. ++ * ++ * When CONFIG_TRANSPARENT_HUGEPAGE=y on x86 32bit PAE, ++ * pmd_read_atomic is allowed to return a not atomic pmdval ++ * (for example pointing to an hugepage that has never been ++ * mapped in the pmd). The below checks will only care about ++ * the low part of the pmd with 32bit PAE x86 anyway, with the ++ * exception of pmd_none(). So the important thing is that if ++ * the low part of the pmd is found null, the high part will ++ * be also null or the pmd_none() check below would be ++ * confused. + */ + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + barrier(); +_ +Subject: Subject: thp: avoid atomic64_read in pmd_read_atomic for 32bit PAE + +Patches currently in -mm which might be from aarcange@redhat.com are + +origin.patch +linux-next.patch +mm-fix-slab-page-_count-corruption-when-using-slub.patch +thp-avoid-atomic64_read-in-pmd_read_atomic-for-32bit-pae.patch +hugetlb-rename-max_hstate-to-hugetlb_max_hstate.patch +hugetlbfs-dont-use-err_ptr-with-vm_fault-values.patch +hugetlbfs-add-an-inline-helper-for-finding-hstate-index.patch +hugetlbfs-add-an-inline-helper-for-finding-hstate-index-fix.patch +hugetlb-use-mmu_gather-instead-of-a-temporary-linked-list-for-accumulating-pages.patch +hugetlb-use-mmu_gather-instead-of-a-temporary-linked-list-for-accumulating-pages-fix.patch +hugetlb-use-mmu_gather-instead-of-a-temporary-linked-list-for-accumulating-pages-fix-fix.patch +hugetlb-avoid-taking-i_mmap_mutex-in-unmap_single_vma-for-hugetlb.patch +hugetlb-simplify-migrate_huge_page.patch +hugetlb-simplify-migrate_huge_page-fix.patch +memcg-add-hugetlb-extension.patch +memcg-add-hugetlb-extension-fix.patch +memcg-add-hugetlb-extension-fix-fix.patch +hugetlb-add-charge-uncharge-calls-for-hugetlb-alloc-free.patch +memcg-track-resource-index-in-cftype-private.patch +hugetlbfs-add-memcg-control-files-for-hugetlbfs.patch +hugetlbfs-add-memcg-control-files-for-hugetlbfs-use-scnprintf-instead-of-sprintf.patch +hugetlbfs-add-memcg-control-files-for-hugetlbfs-use-scnprintf-instead-of-sprintf-fix.patch +hugetlbfs-add-a-list-for-tracking-in-use-hugetlb-pages.patch +memcg-move-hugetlb-resource-count-to-parent-cgroup-on-memcg-removal.patch +memcg-move-hugetlb-resource-count-to-parent-cgroup-on-memcg-removal-fix.patch +memcg-move-hugetlb-resource-count-to-parent-cgroup-on-memcg-removal-fix-fix.patch +hugetlb-migrate-memcg-info-from-oldpage-to-new-page-during-migration.patch +memcg-add-memory-controller-documentation-for-hugetlb-management.patch + +-- +To unsubscribe from this list: send the line "unsubscribe stable" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/utrace.patch b/utrace.patch deleted file mode 100644 index fdf24a472..000000000 --- a/utrace.patch +++ /dev/null @@ -1,4696 +0,0 @@ -From d007ce2c3f1f67624fde5e6b7ccc00566b7df9c3 Mon Sep 17 00:00:00 2001 -From: Oleg Nesterov -Date: Sat, 25 Feb 2012 07:29:40 -0500 -Subject: [PATCH] utrace for 3.3-rc4 kernel, on top of - b52b80023f262ce8a0ffdcb490acb23e8678377a. - -The split-out series is available in the git repository at: - - git@github.com:utrace/linux.git utrace-3.3 - -Oleg Nesterov (31): - utrace: add utrace_init_task/utrace_free_task calls - tracehooks: add utrace hooks - tracehooks: reintroduce tracehook_consider_fatal_signal() - add utrace hooks into sig_ignored() and recalc_sigpending() - restore the EXEC/EXIT/CLONE utrace hooks - utrace: utrace_report_death() can use task_utrace_struct() - restore the DEATH/REAP utrace hooks - utrace: remove jobctl bits - ptrace: take ->siglock around s/TRACED/RUNNING/ - introduce wake_up_quiescent() - introduce ptrace_signal_wake_up() - wait_task_inactive: treat task->state and match_state as bitmasks - introduce TASK_UTRACED state - utrace: use TASK_UTRACED instead of TASK_TRACED - reintroduce tracehook_finish_jctl() as utrace_end_stop() - teach wake_up_quiescent() to do "selective" wake_up - ptrace_stop: do not assume the task is running after wake_up_quiescent() - get_signal_to_deliver: restore/restructure utrace/ptrace signal reporting - utrace_get_signal: s/JOBCTL_STOP_PENDING/JOBCTL_PENDING_MASK/ - introduce ptrace_set_syscall_trace() - introduce PT_SYSCALL_TRACE flag - utrace: don't clear TIF_SYSCALL_TRACE if it is needed by ptrace - introduce task_utrace_lock/task_utrace_unlock - teach ptrace_set_syscall_trace() to play well with utrace - introduce PT_SINGLE_STEP and PT_SINGLE_BLOCK - utrace: finish_resume_report: don't do user_xxx_step() if ptrace_wants_step() - ptrace: shift user_*_step() from ptrace_resume() to ptrace_stop() - ptrace_disable: no need to disable stepping - ptrace_report_syscall: check TIF_SYSCALL_EMU - utrace_resume: check irqs_disabled() to shut up lockdep - utrace: s390: fix the compile problem with traps.c - -Roland McGrath (1): - utrace core - -Tony Breeds (1): - ptrace_report_syscall: check if TIF_SYSCALL_EMU is defined - -Signed-off-by: Oleg Nesterov ---- - Documentation/DocBook/Makefile | 2 +- - Documentation/DocBook/utrace.tmpl | 589 +++++++++ - arch/s390/kernel/traps.c | 6 +- - arch/x86/kernel/ptrace.c | 1 - - fs/exec.c | 5 +- - fs/proc/array.c | 14 +- - include/linux/ptrace.h | 7 + - include/linux/sched.h | 25 +- - include/linux/signal.h | 2 + - include/linux/tracehook.h | 59 +- - include/linux/utrace.h | 774 ++++++++++++ - init/Kconfig | 9 + - kernel/Makefile | 1 + - kernel/exit.c | 5 + - kernel/fork.c | 9 + - kernel/ptrace.c | 57 +- - kernel/sched/core.c | 2 +- - kernel/signal.c | 97 ++- - kernel/utrace.c | 2466 +++++++++++++++++++++++++++++++++++++ - 19 files changed, 4074 insertions(+), 56 deletions(-) - create mode 100644 Documentation/DocBook/utrace.tmpl - create mode 100644 include/linux/utrace.h - create mode 100644 kernel/utrace.c - -diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile -index 66725a3..08ed954 100644 ---- a/Documentation/DocBook/Makefile -+++ b/Documentation/DocBook/Makefile -@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ - genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ - 80211.xml debugobjects.xml sh.xml regulator.xml \ - alsa-driver-api.xml writing-an-alsa-driver.xml \ -- tracepoint.xml drm.xml media_api.xml -+ tracepoint.xml utrace.xml drm.xml media_api.xml - - include $(srctree)/Documentation/DocBook/media/Makefile - -diff --git a/Documentation/DocBook/utrace.tmpl b/Documentation/DocBook/utrace.tmpl -new file mode 100644 -index 0000000..0c40add ---- /dev/null -+++ b/Documentation/DocBook/utrace.tmpl -@@ -0,0 +1,589 @@ -+ -+ -+ -+ -+ -+ The utrace User Debugging Infrastructure -+ -+ -+ -+ -+ utrace concepts -+ -+ Introduction -+ -+ -+ utrace is infrastructure code for tracing -+ and controlling user threads. This is the foundation for writing -+ tracing engines, which can be loadable kernel modules. -+ -+ -+ -+ The basic actors in utrace are the thread -+ and the tracing engine. A tracing engine is some body of code that -+ calls into the <linux/utrace.h> -+ interfaces, represented by a struct -+ utrace_engine_ops. (Usually it's a kernel module, -+ though the legacy ptrace support is a tracing -+ engine that is not in a kernel module.) The interface operates on -+ individual threads (struct task_struct). -+ If an engine wants to treat several threads as a group, that is up -+ to its higher-level code. -+ -+ -+ -+ Tracing begins by attaching an engine to a thread, using -+ utrace_attach_task or -+ utrace_attach_pid. If successful, it returns a -+ pointer that is the handle used in all other calls. -+ -+ -+ -+ -+ Events and Callbacks -+ -+ -+ An attached engine does nothing by default. An engine makes something -+ happen by requesting callbacks via utrace_set_events -+ and poking the thread with utrace_control. -+ The synchronization issues related to these two calls -+ are discussed further below in . -+ -+ -+ -+ Events are specified using the macro -+ UTRACE_EVENT(type). -+ Each event type is associated with a callback in struct -+ utrace_engine_ops. A tracing engine can leave unused -+ callbacks NULL. The only callbacks required -+ are those used by the event flags it sets. -+ -+ -+ -+ Many engines can be attached to each thread. When a thread has an -+ event, each engine gets a callback if it has set the event flag for -+ that event type. For most events, engines are called in the order they -+ attached. Engines that attach after the event has occurred do not get -+ callbacks for that event. This includes any new engines just attached -+ by an existing engine's callback function. Once the sequence of -+ callbacks for that one event has completed, such new engines are then -+ eligible in the next sequence that starts when there is another event. -+ -+ -+ -+ Event reporting callbacks have details particular to the event type, -+ but are all called in similar environments and have the same -+ constraints. Callbacks are made from safe points, where no locks -+ are held, no special resources are pinned (usually), and the -+ user-mode state of the thread is accessible. So, callback code has -+ a pretty free hand. But to be a good citizen, callback code should -+ never block for long periods. It is fine to block in -+ kmalloc and the like, but never wait for i/o or -+ for user mode to do something. If you need the thread to wait, use -+ UTRACE_STOP and return from the callback -+ quickly. When your i/o finishes or whatever, you can use -+ utrace_control to resume the thread. -+ -+ -+ -+ The UTRACE_EVENT(SYSCALL_ENTRY) event is a special -+ case. While other events happen in the kernel when it will return to -+ user mode soon, this event happens when entering the kernel before it -+ will proceed with the work requested from user mode. Because of this -+ difference, the report_syscall_entry callback is -+ special in two ways. For this event, engines are called in reverse of -+ the normal order (this includes the report_quiesce -+ call that precedes a report_syscall_entry call). -+ This preserves the semantics that the last engine to attach is called -+ "closest to user mode"--the engine that is first to see a thread's user -+ state when it enters the kernel is also the last to see that state when -+ the thread returns to user mode. For the same reason, if these -+ callbacks use UTRACE_STOP (see the next section), -+ the thread stops immediately after callbacks rather than only when it's -+ ready to return to user mode; when allowed to resume, it will actually -+ attempt the system call indicated by the register values at that time. -+ -+ -+ -+ -+ Stopping Safely -+ -+ Writing well-behaved callbacks -+ -+ -+ Well-behaved callbacks are important to maintain two essential -+ properties of the interface. The first of these is that unrelated -+ tracing engines should not interfere with each other. If your engine's -+ event callback does not return quickly, then another engine won't get -+ the event notification in a timely manner. The second important -+ property is that tracing should be as noninvasive as possible to the -+ normal operation of the system overall and of the traced thread in -+ particular. That is, attached tracing engines should not perturb a -+ thread's behavior, except to the extent that changing its user-visible -+ state is explicitly what you want to do. (Obviously some perturbation -+ is unavoidable, primarily timing changes, ranging from small delays due -+ to the overhead of tracing, to arbitrary pauses in user code execution -+ when a user stops a thread with a debugger for examination.) Even when -+ you explicitly want the perturbation of making the traced thread block, -+ just blocking directly in your callback has more unwanted effects. For -+ example, the CLONE event callbacks are called when -+ the new child thread has been created but not yet started running; the -+ child can never be scheduled until the CLONE -+ tracing callbacks return. (This allows engines tracing the parent to -+ attach to the child.) If a CLONE event callback -+ blocks the parent thread, it also prevents the child thread from -+ running (even to process a SIGKILL). If what you -+ want is to make both the parent and child block, then use -+ utrace_attach_task on the child and then use -+ UTRACE_STOP on both threads. A more crucial -+ problem with blocking in callbacks is that it can prevent -+ SIGKILL from working. A thread that is blocking -+ due to UTRACE_STOP will still wake up and die -+ immediately when sent a SIGKILL, as all threads -+ should. Relying on the utrace -+ infrastructure rather than on private synchronization calls in event -+ callbacks is an important way to help keep tracing robustly -+ noninvasive. -+ -+ -+ -+ -+ Using <constant>UTRACE_STOP</constant> -+ -+ -+ To control another thread and access its state, it must be stopped -+ with UTRACE_STOP. This means that it is -+ stopped and won't start running again while we access it. When a -+ thread is not already stopped, utrace_control -+ returns -EINPROGRESS and an engine must wait -+ for an event callback when the thread is ready to stop. The thread -+ may be running on another CPU or may be blocked. When it is ready -+ to be examined, it will make callbacks to engines that set the -+ UTRACE_EVENT(QUIESCE) event bit. To wake up an -+ interruptible wait, use UTRACE_INTERRUPT. -+ -+ -+ -+ As long as some engine has used UTRACE_STOP and -+ not called utrace_control to resume the thread, -+ then the thread will remain stopped. SIGKILL -+ will wake it up, but it will not run user code. When the stop is -+ cleared with utrace_control or a callback -+ return value, the thread starts running again. -+ (See also .) -+ -+ -+ -+ -+ -+ -+ Tear-down Races -+ -+ Primacy of <constant>SIGKILL</constant> -+ -+ Ordinarily synchronization issues for tracing engines are kept fairly -+ straightforward by using UTRACE_STOP. You ask a -+ thread to stop, and then once it makes the -+ report_quiesce callback it cannot do anything else -+ that would result in another callback, until you let it with a -+ utrace_control call. This simple arrangement -+ avoids complex and error-prone code in each one of a tracing engine's -+ event callbacks to keep them serialized with the engine's other -+ operations done on that thread from another thread of control. -+ However, giving tracing engines complete power to keep a traced thread -+ stuck in place runs afoul of a more important kind of simplicity that -+ the kernel overall guarantees: nothing can prevent or delay -+ SIGKILL from making a thread die and release its -+ resources. To preserve this important property of -+ SIGKILL, it as a special case can break -+ UTRACE_STOP like nothing else normally can. This -+ includes both explicit SIGKILL signals and the -+ implicit SIGKILL sent to each other thread in the -+ same thread group by a thread doing an exec, or processing a fatal -+ signal, or making an exit_group system call. A -+ tracing engine can prevent a thread from beginning the exit or exec or -+ dying by signal (other than SIGKILL) if it is -+ attached to that thread, but once the operation begins, no tracing -+ engine can prevent or delay all other threads in the same thread group -+ dying. -+ -+ -+ -+ Final callbacks -+ -+ The report_reap callback is always the final event -+ in the life cycle of a traced thread. Tracing engines can use this as -+ the trigger to clean up their own data structures. The -+ report_death callback is always the penultimate -+ event a tracing engine might see; it's seen unless the thread was -+ already in the midst of dying when the engine attached. Many tracing -+ engines will have no interest in when a parent reaps a dead process, -+ and nothing they want to do with a zombie thread once it dies; for -+ them, the report_death callback is the natural -+ place to clean up data structures and detach. To facilitate writing -+ such engines robustly, given the asynchrony of -+ SIGKILL, and without error-prone manual -+ implementation of synchronization schemes, the -+ utrace infrastructure provides some special -+ guarantees about the report_death and -+ report_reap callbacks. It still takes some care -+ to be sure your tracing engine is robust to tear-down races, but these -+ rules make it reasonably straightforward and concise to handle a lot of -+ corner cases correctly. -+ -+ -+ -+ Engine and task pointers -+ -+ The first sort of guarantee concerns the core data structures -+ themselves. struct utrace_engine is -+ a reference-counted data structure. While you hold a reference, an -+ engine pointer will always stay valid so that you can safely pass it to -+ any utrace call. Each call to -+ utrace_attach_task or -+ utrace_attach_pid returns an engine pointer with a -+ reference belonging to the caller. You own that reference until you -+ drop it using utrace_engine_put. There is an -+ implicit reference on the engine while it is attached. So if you drop -+ your only reference, and then use -+ utrace_attach_task without -+ UTRACE_ATTACH_CREATE to look up that same engine, -+ you will get the same pointer with a new reference to replace the one -+ you dropped, just like calling utrace_engine_get. -+ When an engine has been detached, either explicitly with -+ UTRACE_DETACH or implicitly after -+ report_reap, then any references you hold are all -+ that keep the old engine pointer alive. -+ -+ -+ -+ There is nothing a kernel module can do to keep a struct -+ task_struct alive outside of -+ rcu_read_lock. When the task dies and is reaped -+ by its parent (or itself), that structure can be freed so that any -+ dangling pointers you have stored become invalid. -+ utrace will not prevent this, but it can -+ help you detect it safely. By definition, a task that has been reaped -+ has had all its engines detached. All -+ utrace calls can be safely called on a -+ detached engine if the caller holds a reference on that engine pointer, -+ even if the task pointer passed in the call is invalid. All calls -+ return -ESRCH for a detached engine, which tells -+ you that the task pointer you passed could be invalid now. Since -+ utrace_control and -+ utrace_set_events do not block, you can call those -+ inside a rcu_read_lock section and be sure after -+ they don't return -ESRCH that the task pointer is -+ still valid until rcu_read_unlock. The -+ infrastructure never holds task references of its own. Though neither -+ rcu_read_lock nor any other lock is held while -+ making a callback, it's always guaranteed that the struct -+ task_struct and the struct -+ utrace_engine passed as arguments remain valid -+ until the callback function returns. -+ -+ -+ -+ The common means for safely holding task pointers that is available to -+ kernel modules is to use struct pid, which -+ permits put_pid from kernel modules. When using -+ that, the calls utrace_attach_pid, -+ utrace_control_pid, -+ utrace_set_events_pid, and -+ utrace_barrier_pid are available. -+ -+ -+ -+ -+ -+ Serialization of <constant>DEATH</constant> and <constant>REAP</constant> -+ -+ -+ The second guarantee is the serialization of -+ DEATH and REAP event -+ callbacks for a given thread. The actual reaping by the parent -+ (release_task call) can occur simultaneously -+ while the thread is still doing the final steps of dying, including -+ the report_death callback. If a tracing engine -+ has requested both DEATH and -+ REAP event reports, it's guaranteed that the -+ report_reap callback will not be made until -+ after the report_death callback has returned. -+ If the report_death callback itself detaches -+ from the thread, then the report_reap callback -+ will never be made. Thus it is safe for a -+ report_death callback to clean up data -+ structures and detach. -+ -+ -+ -+ Interlock with final callbacks -+ -+ The final sort of guarantee is that a tracing engine will know for sure -+ whether or not the report_death and/or -+ report_reap callbacks will be made for a certain -+ thread. These tear-down races are disambiguated by the error return -+ values of utrace_set_events and -+ utrace_control. Normally -+ utrace_control called with -+ UTRACE_DETACH returns zero, and this means that no -+ more callbacks will be made. If the thread is in the midst of dying, -+ it returns -EALREADY to indicate that the -+ report_death callback may already be in progress; -+ when you get this error, you know that any cleanup your -+ report_death callback does is about to happen or -+ has just happened--note that if the report_death -+ callback does not detach, the engine remains attached until the thread -+ gets reaped. If the thread is in the midst of being reaped, -+ utrace_control returns -ESRCH -+ to indicate that the report_reap callback may -+ already be in progress; this means the engine is implicitly detached -+ when the callback completes. This makes it possible for a tracing -+ engine that has decided asynchronously to detach from a thread to -+ safely clean up its data structures, knowing that no -+ report_death or report_reap -+ callback will try to do the same. utrace_detach -+ returns -ESRCH when the struct -+ utrace_engine has already been detached, but is -+ still a valid pointer because of its reference count. A tracing engine -+ can use this to safely synchronize its own independent multiple threads -+ of control with each other and with its event callbacks that detach. -+ -+ -+ -+ In the same vein, utrace_set_events normally -+ returns zero; if the target thread was stopped before the call, then -+ after a successful call, no event callbacks not requested in the new -+ flags will be made. It fails with -EALREADY if -+ you try to clear UTRACE_EVENT(DEATH) when the -+ report_death callback may already have begun, or if -+ you try to newly set UTRACE_EVENT(DEATH) or -+ UTRACE_EVENT(QUIESCE) when the target is already -+ dead or dying. Like utrace_control, it returns -+ -ESRCH when the report_reap -+ callback may already have begun, or the thread has already been detached -+ (including forcible detach on reaping). This lets the tracing engine -+ know for sure which event callbacks it will or won't see after -+ utrace_set_events has returned. By checking for -+ errors, it can know whether to clean up its data structures immediately -+ or to let its callbacks do the work. -+ -+ -+ -+ Using <function>utrace_barrier</function> -+ -+ When a thread is safely stopped, calling -+ utrace_control with UTRACE_DETACH -+ or calling utrace_set_events to disable some events -+ ensures synchronously that your engine won't get any more of the callbacks -+ that have been disabled (none at all when detaching). But these can also -+ be used while the thread is not stopped, when it might be simultaneously -+ making a callback to your engine. For this situation, these calls return -+ -EINPROGRESS when it's possible a callback is in -+ progress. If you are not prepared to have your old callbacks still run, -+ then you can synchronize to be sure all the old callbacks are finished, -+ using utrace_barrier. This is necessary if the -+ kernel module containing your callback code is going to be unloaded. -+ -+ -+ After using UTRACE_DETACH once, further calls to -+ utrace_control with the same engine pointer will -+ return -ESRCH. In contrast, after getting -+ -EINPROGRESS from -+ utrace_set_events, you can call -+ utrace_set_events again later and if it returns zero -+ then know the old callbacks have finished. -+ -+ -+ Unlike all other calls, utrace_barrier (and -+ utrace_barrier_pid) will accept any engine pointer you -+ hold a reference on, even if UTRACE_DETACH has already -+ been used. After any utrace_control or -+ utrace_set_events call (these do not block), you can -+ call utrace_barrier to block until callbacks have -+ finished. This returns -ESRCH only if the engine is -+ completely detached (finished all callbacks). Otherwise it waits -+ until the thread is definitely not in the midst of a callback to this -+ engine and then returns zero, but can return -+ -ERESTARTSYS if its wait is interrupted. -+ -+ -+ -+ -+ -+ -+ -+utrace core API -+ -+ -+ The utrace API is declared in <linux/utrace.h>. -+ -+ -+!Iinclude/linux/utrace.h -+!Ekernel/utrace.c -+ -+ -+ -+Machine State -+ -+ -+ The task_current_syscall function can be used on any -+ valid struct task_struct at any time, and does -+ not even require that utrace_attach_task was used at all. -+ -+ -+ -+ The other ways to access the registers and other machine-dependent state of -+ a task can only be used on a task that is at a known safe point. The safe -+ points are all the places where utrace_set_events can -+ request callbacks (except for the DEATH and -+ REAP events). So at any event callback, it is safe to -+ examine current. -+ -+ -+ -+ One task can examine another only after a callback in the target task that -+ returns UTRACE_STOP so that task will not return to user -+ mode after the safe point. This guarantees that the task will not resume -+ until the same engine uses utrace_control, unless the -+ task dies suddenly. To examine safely, one must use a pair of calls to -+ utrace_prepare_examine and -+ utrace_finish_examine surrounding the calls to -+ struct user_regset functions or direct examination -+ of task data structures. utrace_prepare_examine returns -+ an error if the task is not properly stopped, or is dead. After a -+ successful examination, the paired utrace_finish_examine -+ call returns an error if the task ever woke up during the examination. If -+ so, any data gathered may be scrambled and should be discarded. This means -+ there was a spurious wake-up (which should not happen), or a sudden death. -+ -+ -+<structname>struct user_regset</structname> -+ -+ -+ The struct user_regset API -+ is declared in <linux/regset.h>. -+ -+ -+!Finclude/linux/regset.h -+ -+ -+ -+ -+ <filename>System Call Information</filename> -+ -+ -+ This function is declared in <linux/ptrace.h>. -+ -+ -+!Elib/syscall.c -+ -+ -+ -+<filename>System Call Tracing</filename> -+ -+ -+ The arch API for system call information is declared in -+ <asm/syscall.h>. -+ Each of these calls can be used only at system call entry tracing, -+ or can be used only at system call exit and the subsequent safe points -+ before returning to user mode. -+ At system call entry tracing means either during a -+ report_syscall_entry callback, -+ or any time after that callback has returned UTRACE_STOP. -+ -+ -+!Finclude/asm-generic/syscall.h -+ -+ -+ -+ -+ -+Kernel Internals -+ -+ -+ This chapter covers the interface to the tracing infrastructure -+ from the core of the kernel and the architecture-specific code. -+ This is for maintainers of the kernel and arch code, and not relevant -+ to using the tracing facilities described in preceding chapters. -+ -+ -+Core Calls In -+ -+ -+ These calls are declared in <linux/tracehook.h>. -+ The core kernel calls these functions at various important places. -+ -+ -+!Finclude/linux/tracehook.h -+ -+ -+ -+Architecture Calls Out -+ -+ -+ An arch that has done all these things sets -+ CONFIG_HAVE_ARCH_TRACEHOOK. -+ This is required to enable the utrace code. -+ -+ -+<filename><asm/ptrace.h></filename> -+ -+ -+ An arch defines these in <asm/ptrace.h> -+ if it supports hardware single-step or block-step features. -+ -+ -+!Finclude/linux/ptrace.h arch_has_single_step arch_has_block_step -+!Finclude/linux/ptrace.h user_enable_single_step user_enable_block_step -+!Finclude/linux/ptrace.h user_disable_single_step -+ -+ -+ -+ -+ <filename><asm/syscall.h></filename> -+ -+ -+ An arch provides <asm/syscall.h> that -+ defines these as inlines, or declares them as exported functions. -+ These interfaces are described in . -+ -+ -+ -+ -+ -+ <filename><linux/tracehook.h></filename> -+ -+ -+ An arch must define TIF_NOTIFY_RESUME -+ and TIF_SYSCALL_TRACE -+ in its <asm/thread_info.h>. -+ The arch code must call the following functions, all declared -+ in <linux/tracehook.h> and -+ described in : -+ -+ -+ -+ tracehook_notify_resume -+ -+ -+ tracehook_report_syscall_entry -+ -+ -+ tracehook_report_syscall_exit -+ -+ -+ tracehook_signal_handler -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c -index 5ce3750..4f0b32f 100644 ---- a/arch/s390/kernel/traps.c -+++ b/arch/s390/kernel/traps.c -@@ -18,7 +18,7 @@ - #include - #include - #include --#include -+#include - #include - #include - #include -@@ -330,7 +330,7 @@ void __kprobes do_per_trap(struct pt_regs *regs) - - if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) - return; -- if (!current->ptrace) -+ if (!tracehook_consider_fatal_signal(current, SIGTRAP)) - return; - info.si_signo = SIGTRAP; - info.si_errno = 0; -@@ -415,7 +415,7 @@ static void __kprobes illegal_op(struct pt_regs *regs) - if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) - return; - if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) { -- if (current->ptrace) { -+ if (tracehook_consider_fatal_signal(current, SIGTRAP)) { - info.si_signo = SIGTRAP; - info.si_errno = 0; - info.si_code = TRAP_BRKPT; -diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c -index 5026738..97687f3 100644 ---- a/arch/x86/kernel/ptrace.c -+++ b/arch/x86/kernel/ptrace.c -@@ -809,7 +809,6 @@ static int ioperm_get(struct task_struct *target, - */ - void ptrace_disable(struct task_struct *child) - { -- user_disable_single_step(child); - #ifdef TIF_SYSCALL_EMU - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); - #endif -diff --git a/fs/exec.c b/fs/exec.c -index 92ce83a..87ff31f 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -1402,9 +1402,12 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) - */ - bprm->recursion_depth = depth; - if (retval >= 0) { -- if (depth == 0) -+ if (depth == 0) { -+ UTRACE_HOOK(current, EXEC, -+ report_exec(fmt, bprm, regs)); - ptrace_event(PTRACE_EVENT_EXEC, - old_pid); -+ } - put_binfmt(fmt); - allow_write_access(bprm->file); - if (bprm->file) -diff --git a/fs/proc/array.c b/fs/proc/array.c -index c602b8d..a700b78 100644 ---- a/fs/proc/array.c -+++ b/fs/proc/array.c -@@ -81,6 +81,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -137,11 +138,12 @@ static const char * const task_state_array[] = { - "D (disk sleep)", /* 2 */ - "T (stopped)", /* 4 */ - "t (tracing stop)", /* 8 */ -- "Z (zombie)", /* 16 */ -- "X (dead)", /* 32 */ -- "x (dead)", /* 64 */ -- "K (wakekill)", /* 128 */ -- "W (waking)", /* 256 */ -+ "t (tracing stop)", /* 16 (stopped by utrace) */ -+ "Z (zombie)", /* 32 */ -+ "X (dead)", /* 64 */ -+ "x (dead)", /* 128 */ -+ "K (wakekill)", /* 256 */ -+ "W (waking)", /* 512 */ - }; - - static inline const char *get_task_state(struct task_struct *tsk) -@@ -192,6 +194,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, - cred->uid, cred->euid, cred->suid, cred->fsuid, - cred->gid, cred->egid, cred->sgid, cred->fsgid); - -+ task_utrace_proc_status(m, p); -+ - task_lock(p); - if (p->files) - fdt = files_fdtable(p->files); -diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index c2f1f6a..236b920 100644 ---- a/include/linux/ptrace.h -+++ b/include/linux/ptrace.h -@@ -104,6 +104,10 @@ - - #define PT_TRACE_MASK 0x000003f4 - -+#define PT_SYSCALL_TRACE 0x00020000 -+#define PT_SINGLE_STEP 0x00040000 -+#define PT_SINGLE_BLOCK 0x00080000 -+ - /* single stepping state bits (used on ARM and PA-RISC) */ - #define PT_SINGLESTEP_BIT 31 - #define PT_SINGLESTEP (1< /* For struct task_struct. */ - #include /* for IS_ERR_VALUE */ - -+extern void ptrace_signal_wake_up(struct task_struct *p, int quiescent); - - extern long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data); -@@ -228,6 +233,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) - - if (unlikely(ptrace) && current->ptrace) { - child->ptrace = current->ptrace; -+ child->ptrace &= -+ ~(PT_SYSCALL_TRACE | PT_SINGLE_STEP | PT_SINGLE_BLOCK); - __ptrace_link(child, current->parent); - - if (child->ptrace & PT_SEIZED) -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 7d379a6..a3c4599 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -185,16 +185,17 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) - #define TASK_UNINTERRUPTIBLE 2 - #define __TASK_STOPPED 4 - #define __TASK_TRACED 8 -+#define __TASK_UTRACED 16 - /* in tsk->exit_state */ --#define EXIT_ZOMBIE 16 --#define EXIT_DEAD 32 -+#define EXIT_ZOMBIE 32 -+#define EXIT_DEAD 64 - /* in tsk->state again */ --#define TASK_DEAD 64 --#define TASK_WAKEKILL 128 --#define TASK_WAKING 256 --#define TASK_STATE_MAX 512 -+#define TASK_DEAD 128 -+#define TASK_WAKEKILL 256 -+#define TASK_WAKING 512 -+#define TASK_STATE_MAX 1024 - --#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKW" -+#define TASK_STATE_TO_CHAR_STR "RSDTtUZXxKW" - - extern char ___assert_task_state[1 - 2*!!( - sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)]; -@@ -203,15 +204,16 @@ extern char ___assert_task_state[1 - 2*!!( - #define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) - #define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED) - #define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED) -+#define TASK_UTRACED (TASK_WAKEKILL | __TASK_UTRACED) - - /* Convenience macros for the sake of wake_up */ - #define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE) --#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED) -+#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) - - /* get_task_state() */ - #define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \ - TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \ -- __TASK_TRACED) -+ __TASK_TRACED | __TASK_UTRACED) - - #define task_is_traced(task) ((task->state & __TASK_TRACED) != 0) - #define task_is_stopped(task) ((task->state & __TASK_STOPPED) != 0) -@@ -1420,6 +1422,11 @@ struct task_struct { - #endif - seccomp_t seccomp; - -+#ifdef CONFIG_UTRACE -+ struct utrace *utrace; -+ unsigned long utrace_flags; -+#endif -+ - /* Thread group tracking */ - u32 parent_exec_id; - u32 self_exec_id; -diff --git a/include/linux/signal.h b/include/linux/signal.h -index 7987ce74..c320549 100644 ---- a/include/linux/signal.h -+++ b/include/linux/signal.h -@@ -239,6 +239,8 @@ static inline int valid_signal(unsigned long sig) - struct timespec; - struct pt_regs; - -+extern int wake_up_quiescent(struct task_struct *p, unsigned int state); -+ - extern int next_signal(struct sigpending *pending, sigset_t *mask); - extern int do_send_sig_info(int sig, struct siginfo *info, - struct task_struct *p, bool group); -diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h -index a71a292..a1bac95 100644 ---- a/include/linux/tracehook.h -+++ b/include/linux/tracehook.h -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - struct linux_binprm; - - /* -@@ -58,8 +59,12 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) - { - int ptrace = current->ptrace; - -- if (!(ptrace & PT_PTRACED)) -- return; -+ if (!(ptrace & PT_SYSCALL_TRACE)) { -+#ifdef TIF_SYSCALL_EMU -+ if (!test_thread_flag(TIF_SYSCALL_EMU)) -+#endif -+ return; -+ } - - ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); - -@@ -96,10 +101,16 @@ static inline void ptrace_report_syscall(struct pt_regs *regs) - static inline __must_check int tracehook_report_syscall_entry( - struct pt_regs *regs) - { -+ if ((task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_ENTRY)) && -+ utrace_report_syscall_entry(regs)) -+ return 1; - ptrace_report_syscall(regs); - return 0; - } - -+#define ptrace_wants_step(task) \ -+ ((task)->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK)) -+ - /** - * tracehook_report_syscall_exit - task has just finished a system call - * @regs: user register state of current task -@@ -119,7 +130,10 @@ static inline __must_check int tracehook_report_syscall_entry( - */ - static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) - { -- if (step) { -+ if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) -+ utrace_report_syscall_exit(regs); -+ -+ if (step && ptrace_wants_step(current)) { - siginfo_t info; - user_single_step_siginfo(current, regs, &info); - force_sig_info(SIGTRAP, &info, current); -@@ -148,10 +162,34 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, - const struct k_sigaction *ka, - struct pt_regs *regs, int stepping) - { -- if (stepping) -+ if (task_utrace_flags(current)) -+ utrace_signal_handler(current, stepping); -+ if (stepping && ptrace_wants_step(current)) - ptrace_notify(SIGTRAP); - } - -+/** -+ * tracehook_consider_fatal_signal - suppress special handling of fatal signal -+ * @task: task receiving the signal -+ * @sig: signal number being sent -+ * -+ * Return nonzero to prevent special handling of this termination signal. -+ * Normally handler for signal is %SIG_DFL. It can be %SIG_IGN if @sig is -+ * ignored, in which case force_sig() is about to reset it to %SIG_DFL. -+ * When this returns zero, this signal might cause a quick termination -+ * that does not give the debugger a chance to intercept the signal. -+ * -+ * Called with or without @task->sighand->siglock held. -+ */ -+static inline int tracehook_consider_fatal_signal(struct task_struct *task, -+ int sig) -+{ -+ if (unlikely(task_utrace_flags(task) & (UTRACE_EVENT(SIGNAL_TERM) | -+ UTRACE_EVENT(SIGNAL_CORE)))) -+ return 1; -+ return task->ptrace != 0; -+} -+ - #ifdef TIF_NOTIFY_RESUME - /** - * set_notify_resume - cause tracehook_notify_resume() to be called -@@ -179,10 +217,21 @@ static inline void set_notify_resume(struct task_struct *task) - * asynchronously, this will be called again before we return to - * user mode. - * -- * Called without locks. -+ * Called without locks. However, on some machines this may be -+ * called with interrupts disabled. - */ - static inline void tracehook_notify_resume(struct pt_regs *regs) - { -+ struct task_struct *task = current; -+ /* -+ * Prevent the following store/load from getting ahead of the -+ * caller which clears TIF_NOTIFY_RESUME. This pairs with the -+ * implicit mb() before setting TIF_NOTIFY_RESUME in -+ * set_notify_resume(). -+ */ -+ smp_mb(); -+ if (task_utrace_flags(task)) -+ utrace_resume(task, regs); - } - #endif /* TIF_NOTIFY_RESUME */ - -diff --git a/include/linux/utrace.h b/include/linux/utrace.h -new file mode 100644 -index 0000000..46959af ---- /dev/null -+++ b/include/linux/utrace.h -@@ -0,0 +1,774 @@ -+/* -+ * utrace infrastructure interface for debugging user processes -+ * -+ * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU General Public License v.2. -+ * -+ * Red Hat Author: Roland McGrath. -+ * -+ * This interface allows for notification of interesting events in a -+ * thread. It also mediates access to thread state such as registers. -+ * Multiple unrelated users can be associated with a single thread. -+ * We call each of these a tracing engine. -+ * -+ * A tracing engine starts by calling utrace_attach_task() or -+ * utrace_attach_pid() on the chosen thread, passing in a set of hooks -+ * (&struct utrace_engine_ops), and some associated data. This produces a -+ * &struct utrace_engine, which is the handle used for all other -+ * operations. An attached engine has its ops vector, its data, and an -+ * event mask controlled by utrace_set_events(). -+ * -+ * For each event bit that is set, that engine will get the -+ * appropriate ops->report_*() callback when the event occurs. The -+ * &struct utrace_engine_ops need not provide callbacks for an event -+ * unless the engine sets one of the associated event bits. -+ */ -+ -+#ifndef _LINUX_UTRACE_H -+#define _LINUX_UTRACE_H 1 -+ -+#include -+#include -+#include -+#include -+ -+struct linux_binprm; -+struct pt_regs; -+struct utrace; -+struct user_regset; -+struct user_regset_view; -+ -+/* -+ * Event bits passed to utrace_set_events(). -+ * These appear in &struct task_struct.@utrace_flags -+ * and &struct utrace_engine.@flags. -+ */ -+enum utrace_events { -+ _UTRACE_EVENT_QUIESCE, /* Thread is available for examination. */ -+ _UTRACE_EVENT_REAP, /* Zombie reaped, no more tracing possible. */ -+ _UTRACE_EVENT_CLONE, /* Successful clone/fork/vfork just done. */ -+ _UTRACE_EVENT_EXEC, /* Successful execve just completed. */ -+ _UTRACE_EVENT_EXIT, /* Thread exit in progress. */ -+ _UTRACE_EVENT_DEATH, /* Thread has died. */ -+ _UTRACE_EVENT_SYSCALL_ENTRY, /* User entered kernel for system call. */ -+ _UTRACE_EVENT_SYSCALL_EXIT, /* Returning to user after system call. */ -+ _UTRACE_EVENT_SIGNAL, /* Signal delivery will run a user handler. */ -+ _UTRACE_EVENT_SIGNAL_IGN, /* No-op signal to be delivered. */ -+ _UTRACE_EVENT_SIGNAL_STOP, /* Signal delivery will suspend. */ -+ _UTRACE_EVENT_SIGNAL_TERM, /* Signal delivery will terminate. */ -+ _UTRACE_EVENT_SIGNAL_CORE, /* Signal delivery will dump core. */ -+ _UTRACE_EVENT_JCTL, /* Job control stop or continue completed. */ -+ _UTRACE_NEVENTS -+}; -+#define UTRACE_EVENT(type) (1UL << _UTRACE_EVENT_##type) -+ -+/* -+ * All the kinds of signal events. -+ * These all use the @report_signal() callback. -+ */ -+#define UTRACE_EVENT_SIGNAL_ALL (UTRACE_EVENT(SIGNAL) \ -+ | UTRACE_EVENT(SIGNAL_IGN) \ -+ | UTRACE_EVENT(SIGNAL_STOP) \ -+ | UTRACE_EVENT(SIGNAL_TERM) \ -+ | UTRACE_EVENT(SIGNAL_CORE)) -+/* -+ * Both kinds of syscall events; these call the @report_syscall_entry() -+ * and @report_syscall_exit() callbacks, respectively. -+ */ -+#define UTRACE_EVENT_SYSCALL \ -+ (UTRACE_EVENT(SYSCALL_ENTRY) | UTRACE_EVENT(SYSCALL_EXIT)) -+ -+/* -+ * The event reports triggered synchronously by task death. -+ */ -+#define _UTRACE_DEATH_EVENTS (UTRACE_EVENT(DEATH) | UTRACE_EVENT(QUIESCE)) -+ -+/* -+ * Hooks in call these entry points to the utrace dispatch. -+ */ -+void utrace_free_task(struct task_struct *); -+bool utrace_interrupt_pending(void); -+void utrace_resume(struct task_struct *, struct pt_regs *); -+void utrace_finish_stop(void); -+void utrace_maybe_reap(struct task_struct *, struct utrace *, bool); -+int utrace_get_signal(struct task_struct *, struct pt_regs *, -+ siginfo_t *, struct k_sigaction *); -+void utrace_report_clone(unsigned long, struct task_struct *); -+void utrace_finish_vfork(struct task_struct *); -+void utrace_report_exit(long *exit_code); -+void utrace_report_death(struct task_struct *, bool, int); -+void utrace_report_jctl(int notify, int type); -+void utrace_report_exec(struct linux_binfmt *, struct linux_binprm *, -+ struct pt_regs *regs); -+bool utrace_report_syscall_entry(struct pt_regs *); -+void utrace_report_syscall_exit(struct pt_regs *); -+void utrace_signal_handler(struct task_struct *, int); -+ -+#define UTRACE_FLAG(task, ev) (task_utrace_flags(task) & UTRACE_EVENT(ev)) -+ -+#define UTRACE_HOOK(task, ev, callback) \ -+ do { \ -+ if (UTRACE_FLAG(task, ev)) \ -+ utrace_ ## callback; \ -+ } while (0) -+ -+#ifndef CONFIG_UTRACE -+ -+static inline void task_utrace_lock(struct task_struct *task) -+{ -+} -+static inline void task_utrace_unlock(struct task_struct *task) -+{ -+} -+/* -+ * uses these accessors to avoid #ifdef CONFIG_UTRACE. -+ */ -+static inline unsigned long task_utrace_flags(struct task_struct *task) -+{ -+ return 0; -+} -+static inline struct utrace *task_utrace_struct(struct task_struct *task) -+{ -+ return NULL; -+} -+static inline void utrace_init_task(struct task_struct *child) -+{ -+} -+ -+static inline void task_utrace_proc_status(struct seq_file *m, -+ struct task_struct *p) -+{ -+} -+ -+#else /* CONFIG_UTRACE */ -+ -+extern void task_utrace_lock(struct task_struct *task); -+extern void task_utrace_unlock(struct task_struct *task); -+ -+static inline unsigned long task_utrace_flags(struct task_struct *task) -+{ -+ return task->utrace_flags; -+} -+ -+static inline struct utrace *task_utrace_struct(struct task_struct *task) -+{ -+ struct utrace *utrace; -+ -+ /* -+ * This barrier ensures that any prior load of task->utrace_flags -+ * is ordered before this load of task->utrace. We use those -+ * utrace_flags checks in the hot path to decide to call into -+ * the utrace code. The first attach installs task->utrace before -+ * setting task->utrace_flags nonzero with implicit barrier in -+ * between, see utrace_add_engine(). -+ */ -+ smp_rmb(); -+ utrace = task->utrace; -+ -+ smp_read_barrier_depends(); /* See utrace_task_alloc(). */ -+ return utrace; -+} -+ -+static inline void utrace_init_task(struct task_struct *task) -+{ -+ task->utrace_flags = 0; -+ task->utrace = NULL; -+} -+ -+void task_utrace_proc_status(struct seq_file *m, struct task_struct *p); -+ -+ -+/* -+ * Version number of the API defined in this file. This will change -+ * whenever a tracing engine's code would need some updates to keep -+ * working. We maintain this here for the benefit of tracing engine code -+ * that is developed concurrently with utrace API improvements before they -+ * are merged into the kernel, making LINUX_VERSION_CODE checks unwieldy. -+ */ -+#define UTRACE_API_VERSION 20091216 -+ -+/** -+ * enum utrace_resume_action - engine's choice of action for a traced task -+ * @UTRACE_STOP: Stay quiescent after callbacks. -+ * @UTRACE_INTERRUPT: Make @report_signal() callback soon. -+ * @UTRACE_REPORT: Make some callback soon. -+ * @UTRACE_SINGLESTEP: Resume in user mode for one instruction. -+ * @UTRACE_BLOCKSTEP: Resume in user mode until next branch. -+ * @UTRACE_RESUME: Resume normally in user mode. -+ * @UTRACE_DETACH: Detach my engine (implies %UTRACE_RESUME). -+ * -+ * See utrace_control() for detailed descriptions of each action. This is -+ * encoded in the @action argument and the return value for every callback -+ * with a &u32 return value. -+ * -+ * The order of these is important. When there is more than one engine, -+ * each supplies its choice and the smallest value prevails. -+ */ -+enum utrace_resume_action { -+ UTRACE_STOP, -+ UTRACE_INTERRUPT, -+ UTRACE_REPORT, -+ UTRACE_SINGLESTEP, -+ UTRACE_BLOCKSTEP, -+ UTRACE_RESUME, -+ UTRACE_DETACH, -+ UTRACE_RESUME_MAX -+}; -+#define UTRACE_RESUME_BITS (ilog2(UTRACE_RESUME_MAX) + 1) -+#define UTRACE_RESUME_MASK ((1 << UTRACE_RESUME_BITS) - 1) -+ -+/** -+ * utrace_resume_action - &enum utrace_resume_action from callback action -+ * @action: &u32 callback @action argument or return value -+ * -+ * This extracts the &enum utrace_resume_action from @action, -+ * which is the @action argument to a &struct utrace_engine_ops -+ * callback or the return value from one. -+ */ -+static inline enum utrace_resume_action utrace_resume_action(u32 action) -+{ -+ return action & UTRACE_RESUME_MASK; -+} -+ -+/** -+ * enum utrace_signal_action - disposition of signal -+ * @UTRACE_SIGNAL_DELIVER: Deliver according to sigaction. -+ * @UTRACE_SIGNAL_IGN: Ignore the signal. -+ * @UTRACE_SIGNAL_TERM: Terminate the process. -+ * @UTRACE_SIGNAL_CORE: Terminate with core dump. -+ * @UTRACE_SIGNAL_STOP: Deliver as absolute stop. -+ * @UTRACE_SIGNAL_TSTP: Deliver as job control stop. -+ * @UTRACE_SIGNAL_REPORT: Reporting before pending signals. -+ * @UTRACE_SIGNAL_HANDLER: Reporting after signal handler setup. -+ * -+ * This is encoded in the @action argument and the return value for -+ * a @report_signal() callback. It says what will happen to the -+ * signal described by the &siginfo_t parameter to the callback. -+ * -+ * The %UTRACE_SIGNAL_REPORT value is used in an @action argument when -+ * a tracing report is being made before dequeuing any pending signal. -+ * If this is immediately after a signal handler has been set up, then -+ * %UTRACE_SIGNAL_HANDLER is used instead. A @report_signal callback -+ * that uses %UTRACE_SIGNAL_DELIVER|%UTRACE_SINGLESTEP will ensure -+ * it sees a %UTRACE_SIGNAL_HANDLER report. -+ */ -+enum utrace_signal_action { -+ UTRACE_SIGNAL_DELIVER = 0x00, -+ UTRACE_SIGNAL_IGN = 0x10, -+ UTRACE_SIGNAL_TERM = 0x20, -+ UTRACE_SIGNAL_CORE = 0x30, -+ UTRACE_SIGNAL_STOP = 0x40, -+ UTRACE_SIGNAL_TSTP = 0x50, -+ UTRACE_SIGNAL_REPORT = 0x60, -+ UTRACE_SIGNAL_HANDLER = 0x70 -+}; -+#define UTRACE_SIGNAL_MASK 0xf0 -+#define UTRACE_SIGNAL_HOLD 0x100 /* Flag, push signal back on queue. */ -+ -+/** -+ * utrace_signal_action - &enum utrace_signal_action from callback action -+ * @action: @report_signal callback @action argument or return value -+ * -+ * This extracts the &enum utrace_signal_action from @action, which -+ * is the @action argument to a @report_signal callback or the -+ * return value from one. -+ */ -+static inline enum utrace_signal_action utrace_signal_action(u32 action) -+{ -+ return action & UTRACE_SIGNAL_MASK; -+} -+ -+/** -+ * enum utrace_syscall_action - disposition of system call attempt -+ * @UTRACE_SYSCALL_RUN: Run the system call. -+ * @UTRACE_SYSCALL_ABORT: Don't run the system call. -+ * -+ * This is encoded in the @action argument and the return value for -+ * a @report_syscall_entry callback. -+ */ -+enum utrace_syscall_action { -+ UTRACE_SYSCALL_RUN = 0x00, -+ UTRACE_SYSCALL_ABORT = 0x10 -+}; -+#define UTRACE_SYSCALL_MASK 0xf0 -+#define UTRACE_SYSCALL_RESUMED 0x100 /* Flag, report_syscall_entry() repeats */ -+ -+/** -+ * utrace_syscall_action - &enum utrace_syscall_action from callback action -+ * @action: @report_syscall_entry callback @action or return value -+ * -+ * This extracts the &enum utrace_syscall_action from @action, which -+ * is the @action argument to a @report_syscall_entry callback or the -+ * return value from one. -+ */ -+static inline enum utrace_syscall_action utrace_syscall_action(u32 action) -+{ -+ return action & UTRACE_SYSCALL_MASK; -+} -+ -+/* -+ * Flags for utrace_attach_task() and utrace_attach_pid(). -+ */ -+#define UTRACE_ATTACH_MATCH_OPS 0x0001 /* Match engines on ops. */ -+#define UTRACE_ATTACH_MATCH_DATA 0x0002 /* Match engines on data. */ -+#define UTRACE_ATTACH_MATCH_MASK 0x000f -+#define UTRACE_ATTACH_CREATE 0x0010 /* Attach a new engine. */ -+#define UTRACE_ATTACH_EXCLUSIVE 0x0020 /* Refuse if existing match. */ -+#define UTRACE_ATTACH_ATOMIC 0x0040 /* For _CREATE, don't sleep */ -+ -+/** -+ * struct utrace_engine - per-engine structure -+ * @ops: &struct utrace_engine_ops pointer passed to utrace_attach_task() -+ * @data: engine-private &void * passed to utrace_attach_task() -+ * @flags: event mask set by utrace_set_events() plus internal flag bits -+ * -+ * The task itself never has to worry about engines detaching while -+ * it's doing event callbacks. These structures are removed from the -+ * task's active list only when it's stopped, or by the task itself. -+ * -+ * utrace_engine_get() and utrace_engine_put() maintain a reference count. -+ * When it drops to zero, the structure is freed. One reference is held -+ * implicitly while the engine is attached to its task. -+ */ -+struct utrace_engine { -+/* private: */ -+ struct kref kref; -+ void (*release)(void *); -+ struct list_head entry; -+ -+/* public: */ -+ const struct utrace_engine_ops *ops; -+ void *data; -+ -+ unsigned long flags; -+}; -+ -+/** -+ * utrace_engine_get - acquire a reference on a &struct utrace_engine -+ * @engine: &struct utrace_engine pointer -+ * -+ * You must hold a reference on @engine, and you get another. -+ */ -+static inline void utrace_engine_get(struct utrace_engine *engine) -+{ -+ kref_get(&engine->kref); -+} -+ -+void __utrace_engine_release(struct kref *); -+ -+/** -+ * utrace_engine_put - release a reference on a &struct utrace_engine -+ * @engine: &struct utrace_engine pointer -+ * -+ * You must hold a reference on @engine, and you lose that reference. -+ * If it was the last one, @engine becomes an invalid pointer. -+ */ -+static inline void utrace_engine_put(struct utrace_engine *engine) -+{ -+ kref_put(&engine->kref, __utrace_engine_release); -+} -+ -+/** -+ * struct utrace_engine_ops - tracing engine callbacks -+ * -+ * Each @report_*() callback corresponds to an %UTRACE_EVENT(*) bit. -+ * utrace_set_events() calls on @engine choose which callbacks will -+ * be made to @engine from @task. -+ * -+ * Most callbacks take an @action argument, giving the resume action -+ * chosen by other tracing engines. All callbacks take an @engine -+ * argument. The @report_reap callback takes a @task argument that -+ * might or might not be @current. All other @report_* callbacks -+ * report an event in the @current task. -+ * -+ * For some calls, @action also includes bits specific to that event -+ * and utrace_resume_action() is used to extract the resume action. -+ * This shows what would happen if @engine wasn't there, or will if -+ * the callback's return value uses %UTRACE_RESUME. This always -+ * starts as %UTRACE_RESUME when no other tracing is being done on -+ * this task. -+ * -+ * All return values contain &enum utrace_resume_action bits. For -+ * some calls, other bits specific to that kind of event are added to -+ * the resume action bits with OR. These are the same bits used in -+ * the @action argument. The resume action returned by a callback -+ * does not override previous engines' choices, it only says what -+ * @engine wants done. What @current actually does is the action that's -+ * most constrained among the choices made by all attached engines. -+ * See utrace_control() for more information on the actions. -+ * -+ * When %UTRACE_STOP is used in @report_syscall_entry, then @current -+ * stops before attempting the system call. In this case, another -+ * @report_syscall_entry callback will follow after @current resumes if -+ * %UTRACE_REPORT or %UTRACE_INTERRUPT was returned by some callback -+ * or passed to utrace_control(). In a second or later callback, -+ * %UTRACE_SYSCALL_RESUMED is set in the @action argument to indicate -+ * a repeat callback still waiting to attempt the same system call -+ * invocation. This repeat callback gives each engine an opportunity -+ * to reexamine registers another engine might have changed while -+ * @current was held in %UTRACE_STOP. -+ * -+ * In other cases, the resume action does not take effect until @current -+ * is ready to check for signals and return to user mode. If there -+ * are more callbacks to be made, the last round of calls determines -+ * the final action. A @report_quiesce callback with @event zero, or -+ * a @report_signal callback, will always be the last one made before -+ * @current resumes. Only %UTRACE_STOP is "sticky"--if @engine returned -+ * %UTRACE_STOP then @current stays stopped unless @engine returns -+ * different from a following callback. -+ * -+ * The report_death() and report_reap() callbacks do not take @action -+ * arguments, and only %UTRACE_DETACH is meaningful in the return value -+ * from a report_death() callback. None of the resume actions applies -+ * to a dead thread. -+ * -+ * All @report_*() hooks are called with no locks held, in a generally -+ * safe environment when we will be returning to user mode soon (or just -+ * entered the kernel). It is fine to block for memory allocation and -+ * the like, but all hooks are asynchronous and must not block on -+ * external events! If you want the thread to block, use %UTRACE_STOP -+ * in your hook's return value; then later wake it up with utrace_control(). -+ * -+ * @report_quiesce: -+ * Requested by %UTRACE_EVENT(%QUIESCE). -+ * This does not indicate any event, but just that @current is in a -+ * safe place for examination. This call is made before each specific -+ * event callback, except for @report_reap. The @event argument gives -+ * the %UTRACE_EVENT(@which) value for the event occurring. This -+ * callback might be made for events @engine has not requested, if -+ * some other engine is tracing the event; calling utrace_set_events() -+ * call here can request the immediate callback for this occurrence of -+ * @event. @event is zero when there is no other event, @current is -+ * now ready to check for signals and return to user mode, and some -+ * engine has used %UTRACE_REPORT or %UTRACE_INTERRUPT to request this -+ * callback. For this case, if @report_signal is not %NULL, the -+ * @report_quiesce callback may be replaced with a @report_signal -+ * callback passing %UTRACE_SIGNAL_REPORT in its @action argument, -+ * whenever @current is entering the signal-check path anyway. -+ * -+ * @report_signal: -+ * Requested by %UTRACE_EVENT(%SIGNAL_*) or %UTRACE_EVENT(%QUIESCE). -+ * Use utrace_signal_action() and utrace_resume_action() on @action. -+ * The signal action is %UTRACE_SIGNAL_REPORT when some engine has -+ * used %UTRACE_REPORT or %UTRACE_INTERRUPT; the callback can choose -+ * to stop or to deliver an artificial signal, before pending signals. -+ * It's %UTRACE_SIGNAL_HANDLER instead when signal handler setup just -+ * finished (after a previous %UTRACE_SIGNAL_DELIVER return); this -+ * serves in lieu of any %UTRACE_SIGNAL_REPORT callback requested by -+ * %UTRACE_REPORT or %UTRACE_INTERRUPT, and is also implicitly -+ * requested by %UTRACE_SINGLESTEP or %UTRACE_BLOCKSTEP into the -+ * signal delivery. The other signal actions indicate a signal about -+ * to be delivered; the previous engine's return value sets the signal -+ * action seen by the the following engine's callback. The @info data -+ * can be changed at will, including @info->si_signo. The settings in -+ * @return_ka determines what %UTRACE_SIGNAL_DELIVER does. @orig_ka -+ * is what was in force before other tracing engines intervened, and -+ * it's %NULL when this report began as %UTRACE_SIGNAL_REPORT or -+ * %UTRACE_SIGNAL_HANDLER. For a report without a new signal, @info -+ * is left uninitialized and must be set completely by an engine that -+ * chooses to deliver a signal; if there was a previous @report_signal -+ * callback ending in %UTRACE_STOP and it was just resumed using -+ * %UTRACE_REPORT or %UTRACE_INTERRUPT, then @info is left unchanged -+ * from the previous callback. In this way, the original signal can -+ * be left in @info while returning %UTRACE_STOP|%UTRACE_SIGNAL_IGN -+ * and then found again when resuming with %UTRACE_INTERRUPT. -+ * The %UTRACE_SIGNAL_HOLD flag bit can be OR'd into the return value, -+ * and might be in @action if the previous engine returned it. This -+ * flag asks that the signal in @info be pushed back on @current's queue -+ * so that it will be seen again after whatever action is taken now. -+ * -+ * @report_clone: -+ * Requested by %UTRACE_EVENT(%CLONE). -+ * Event reported for parent, before the new task @child might run. -+ * @clone_flags gives the flags used in the clone system call, or -+ * equivalent flags for a fork() or vfork() system call. This -+ * function can use utrace_attach_task() on @child. Then passing -+ * %UTRACE_STOP to utrace_control() on @child here keeps the child -+ * stopped before it ever runs in user mode, %UTRACE_REPORT or -+ * %UTRACE_INTERRUPT ensures a callback from @child before it -+ * starts in user mode. -+ * -+ * @report_jctl: -+ * Requested by %UTRACE_EVENT(%JCTL). -+ * Job control event; @type is %CLD_STOPPED or %CLD_CONTINUED, -+ * indicating whether we are stopping or resuming now. If @notify -+ * is nonzero, @current is the last thread to stop and so will send -+ * %SIGCHLD to its parent after this callback; @notify reflects -+ * what the parent's %SIGCHLD has in @si_code, which can sometimes -+ * be %CLD_STOPPED even when @type is %CLD_CONTINUED. -+ * -+ * @report_exec: -+ * Requested by %UTRACE_EVENT(%EXEC). -+ * An execve system call has succeeded and the new program is about to -+ * start running. The initial user register state is handy to be tweaked -+ * directly in @regs. @fmt and @bprm gives the details of this exec. -+ * -+ * @report_syscall_entry: -+ * Requested by %UTRACE_EVENT(%SYSCALL_ENTRY). -+ * Thread has entered the kernel to request a system call. -+ * The user register state is handy to be tweaked directly in @regs. -+ * The @action argument contains an &enum utrace_syscall_action, -+ * use utrace_syscall_action() to extract it. The return value -+ * overrides the last engine's action for the system call. -+ * If the final action is %UTRACE_SYSCALL_ABORT, no system call -+ * is made. The details of the system call being attempted can -+ * be fetched here with syscall_get_nr() and syscall_get_arguments(). -+ * The parameter registers can be changed with syscall_set_arguments(). -+ * See above about the %UTRACE_SYSCALL_RESUMED flag in @action. -+ * Use %UTRACE_REPORT in the return value to guarantee you get -+ * another callback (with %UTRACE_SYSCALL_RESUMED flag) in case -+ * @current stops with %UTRACE_STOP before attempting the system call. -+ * -+ * @report_syscall_exit: -+ * Requested by %UTRACE_EVENT(%SYSCALL_EXIT). -+ * Thread is about to leave the kernel after a system call request. -+ * The user register state is handy to be tweaked directly in @regs. -+ * The results of the system call attempt can be examined here using -+ * syscall_get_error() and syscall_get_return_value(). It is safe -+ * here to call syscall_set_return_value() or syscall_rollback(). -+ * -+ * @report_exit: -+ * Requested by %UTRACE_EVENT(%EXIT). -+ * Thread is exiting and cannot be prevented from doing so, -+ * but all its state is still live. The @code value will be -+ * the wait result seen by the parent, and can be changed by -+ * this engine or others. The @orig_code value is the real -+ * status, not changed by any tracing engine. Returning %UTRACE_STOP -+ * here keeps @current stopped before it cleans up its state and dies, -+ * so it can be examined by other processes. When @current is allowed -+ * to run, it will die and get to the @report_death callback. -+ * -+ * @report_death: -+ * Requested by %UTRACE_EVENT(%DEATH). -+ * Thread is really dead now. It might be reaped by its parent at -+ * any time, or self-reap immediately. Though the actual reaping -+ * may happen in parallel, a report_reap() callback will always be -+ * ordered after a report_death() callback. -+ * -+ * @report_reap: -+ * Requested by %UTRACE_EVENT(%REAP). -+ * Called when someone reaps the dead task (parent, init, or self). -+ * This means the parent called wait, or else this was a detached -+ * thread or a process whose parent ignores SIGCHLD. -+ * No more callbacks are made after this one. -+ * The engine is always detached. -+ * There is nothing more a tracing engine can do about this thread. -+ * After this callback, the @engine pointer will become invalid. -+ * The @task pointer may become invalid if get_task_struct() hasn't -+ * been used to keep it alive. -+ * An engine should always request this callback if it stores the -+ * @engine pointer or stores any pointer in @engine->data, so it -+ * can clean up its data structures. -+ * Unlike other callbacks, this can be called from the parent's context -+ * rather than from the traced thread itself--it must not delay the -+ * parent by blocking. -+ * -+ * @release: -+ * If not %NULL, this is called after the last utrace_engine_put() -+ * call for a &struct utrace_engine, which could be implicit after -+ * a %UTRACE_DETACH return from another callback. Its argument is -+ * the engine's @data member. -+ */ -+struct utrace_engine_ops { -+ u32 (*report_quiesce)(u32 action, struct utrace_engine *engine, -+ unsigned long event); -+ u32 (*report_signal)(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs, -+ siginfo_t *info, -+ const struct k_sigaction *orig_ka, -+ struct k_sigaction *return_ka); -+ u32 (*report_clone)(u32 action, struct utrace_engine *engine, -+ unsigned long clone_flags, -+ struct task_struct *child); -+ u32 (*report_jctl)(u32 action, struct utrace_engine *engine, -+ int type, int notify); -+ u32 (*report_exec)(u32 action, struct utrace_engine *engine, -+ const struct linux_binfmt *fmt, -+ const struct linux_binprm *bprm, -+ struct pt_regs *regs); -+ u32 (*report_syscall_entry)(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs); -+ u32 (*report_syscall_exit)(u32 action, struct utrace_engine *engine, -+ struct pt_regs *regs); -+ u32 (*report_exit)(u32 action, struct utrace_engine *engine, -+ long orig_code, long *code); -+ u32 (*report_death)(struct utrace_engine *engine, -+ bool group_dead, int signal); -+ void (*report_reap)(struct utrace_engine *engine, -+ struct task_struct *task); -+ void (*release)(void *data); -+}; -+ -+/** -+ * struct utrace_examiner - private state for using utrace_prepare_examine() -+ * -+ * The members of &struct utrace_examiner are private to the implementation. -+ * This data type holds the state from a call to utrace_prepare_examine() -+ * to be used by a call to utrace_finish_examine(). -+ */ -+struct utrace_examiner { -+/* private: */ -+ long state; -+ unsigned long ncsw; -+}; -+ -+/* -+ * These are the exported entry points for tracing engines to use. -+ * See kernel/utrace.c for their kerneldoc comments with interface details. -+ */ -+struct utrace_engine *utrace_attach_task(struct task_struct *, int, -+ const struct utrace_engine_ops *, -+ void *); -+struct utrace_engine *utrace_attach_pid(struct pid *, int, -+ const struct utrace_engine_ops *, -+ void *); -+int __must_check utrace_control(struct task_struct *, -+ struct utrace_engine *, -+ enum utrace_resume_action); -+int __must_check utrace_set_events(struct task_struct *, -+ struct utrace_engine *, -+ unsigned long eventmask); -+int __must_check utrace_barrier(struct task_struct *, -+ struct utrace_engine *); -+int __must_check utrace_prepare_examine(struct task_struct *, -+ struct utrace_engine *, -+ struct utrace_examiner *); -+int __must_check utrace_finish_examine(struct task_struct *, -+ struct utrace_engine *, -+ struct utrace_examiner *); -+ -+/** -+ * utrace_control_pid - control a thread being traced by a tracing engine -+ * @pid: thread to affect -+ * @engine: attached engine to affect -+ * @action: &enum utrace_resume_action for thread to do -+ * -+ * This is the same as utrace_control(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+static inline __must_check int utrace_control_pid( -+ struct pid *pid, struct utrace_engine *engine, -+ enum utrace_resume_action action) -+{ -+ /* -+ * We don't bother with rcu_read_lock() here to protect the -+ * task_struct pointer, because utrace_control will return -+ * -ESRCH without looking at that pointer if the engine is -+ * already detached. A task_struct pointer can't die before -+ * all the engines are detached in release_task() first. -+ */ -+ struct task_struct *task = pid_task(pid, PIDTYPE_PID); -+ return unlikely(!task) ? -ESRCH : utrace_control(task, engine, action); -+} -+ -+/** -+ * utrace_set_events_pid - choose which event reports a tracing engine gets -+ * @pid: thread to affect -+ * @engine: attached engine to affect -+ * @eventmask: new event mask -+ * -+ * This is the same as utrace_set_events(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+static inline __must_check int utrace_set_events_pid( -+ struct pid *pid, struct utrace_engine *engine, unsigned long eventmask) -+{ -+ struct task_struct *task = pid_task(pid, PIDTYPE_PID); -+ return unlikely(!task) ? -ESRCH : -+ utrace_set_events(task, engine, eventmask); -+} -+ -+/** -+ * utrace_barrier_pid - synchronize with simultaneous tracing callbacks -+ * @pid: thread to affect -+ * @engine: engine to affect (can be detached) -+ * -+ * This is the same as utrace_barrier(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+static inline __must_check int utrace_barrier_pid(struct pid *pid, -+ struct utrace_engine *engine) -+{ -+ struct task_struct *task = pid_task(pid, PIDTYPE_PID); -+ return unlikely(!task) ? -ESRCH : utrace_barrier(task, engine); -+} -+ -+#endif /* CONFIG_UTRACE */ -+ -+static inline void utrace_release_task(struct task_struct *task) -+{ -+ /* see utrace_add_engine() about this barrier */ -+ smp_mb(); -+ if (task_utrace_flags(task)) -+ utrace_maybe_reap(task, task_utrace_struct(task), true); -+} -+ -+static inline void utrace_exit_notify(struct task_struct *task, -+ int signal, int group_dead) -+{ -+ /* -+ * If utrace_set_events() was just called to enable -+ * UTRACE_EVENT(DEATH), then we are obliged to call -+ * utrace_report_death() and not miss it. utrace_set_events() -+ * checks @task->exit_state under tasklist_lock to synchronize -+ * with exit_notify(), the caller. -+ */ -+ if (task_utrace_flags(task) & _UTRACE_DEATH_EVENTS) -+ utrace_report_death(task, group_dead, signal); -+} -+ -+/** -+ * utrace_end_stop - report about return from STOPPED/TRACED -+ * -+ * This is called by do_signal_stop() and ptrace_stop after wakeup. -+ */ -+static inline void utrace_end_stop(void) -+{ -+ if (task_utrace_flags(current)) -+ utrace_finish_stop(); -+} -+ -+/** -+ * utrace_hook_signal - deliver synthetic signal to traced task -+ * @task: @current -+ * @regs: task_pt_regs(@current) -+ * @info: details of synthetic signal -+ * @return_ka: sigaction for synthetic signal -+ * -+ * Return zero to check for a real pending signal normally. -+ * Return -1 after releasing the siglock to repeat the check. -+ * Return a signal number to induce an artificial signal delivery, -+ * setting *@info and *@return_ka to specify its details and behavior. -+ * -+ * The @return_ka->sa_handler value controls the disposition of the -+ * signal, no matter the signal number. For %SIG_DFL, the return value -+ * is a representative signal to indicate the behavior (e.g. %SIGTERM -+ * for death, %SIGQUIT for core dump, %SIGSTOP for job control stop, -+ * %SIGTSTP for stop unless in an orphaned pgrp), but the signal number -+ * reported will be @info->si_signo instead. -+ * -+ * Called with @task->sighand->siglock held, before dequeuing pending signals. -+ */ -+static inline int utrace_hook_signal(struct task_struct *task, -+ struct pt_regs *regs, -+ siginfo_t *info, -+ struct k_sigaction *return_ka) -+{ -+ if (unlikely(task_utrace_flags(task))) -+ return utrace_get_signal(task, regs, info, return_ka); -+ return 0; -+} -+ -+#endif /* linux/utrace.h */ -diff --git a/init/Kconfig b/init/Kconfig -index 3f42cd6..5f4f92e 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -386,6 +386,15 @@ config AUDIT_LOGINUID_IMMUTABLE - one to drop potentially dangerous capabilites from the login tasks, - but may not be backwards compatible with older init systems. - -+config UTRACE -+ bool "Infrastructure for tracing and debugging user processes" -+ depends on EXPERIMENTAL -+ depends on HAVE_ARCH_TRACEHOOK -+ help -+ Enable the utrace process tracing interface. This is an internal -+ kernel interface exported to kernel modules, to track events in -+ user threads, extract and change user thread state. -+ - source "kernel/irq/Kconfig" - - menu "RCU Subsystem" -diff --git a/kernel/Makefile b/kernel/Makefile -index 2d9de86..6c6749d 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -67,6 +67,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o - obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o - obj-$(CONFIG_SMP) += stop_machine.o - obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o -+obj-$(CONFIG_UTRACE) += utrace.o - obj-$(CONFIG_AUDIT) += audit.o auditfilter.o - obj-$(CONFIG_AUDITSYSCALL) += auditsc.o - obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o -diff --git a/kernel/exit.c b/kernel/exit.c -index 4b4042f..b1e0518 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -169,6 +169,8 @@ void release_task(struct task_struct * p) - struct task_struct *leader; - int zap_leader; - repeat: -+ utrace_release_task(p); -+ - /* don't need to get the RCU readlock here - the process is dead and - * can't be modifying its own credentials. But shut RCU-lockdep up */ - rcu_read_lock(); -@@ -857,6 +859,8 @@ static void exit_notify(struct task_struct *tsk, int group_dead) - wake_up_process(tsk->signal->group_exit_task); - write_unlock_irq(&tasklist_lock); - -+ utrace_exit_notify(tsk, autoreap ? -1 : SIGCHLD, group_dead); -+ - /* If the process is dead, release it - nobody will wait for it */ - if (autoreap) - release_task(tsk); -@@ -910,6 +914,7 @@ void do_exit(long code) - */ - set_fs(USER_DS); - -+ UTRACE_HOOK(current, EXIT, report_exit(&code)); - ptrace_event(PTRACE_EVENT_EXIT, code); - - validate_creds_for_do_exit(tsk); -diff --git a/kernel/fork.c b/kernel/fork.c -index e2cd3e2..fa40928 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -67,6 +67,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -170,6 +171,8 @@ void free_task(struct task_struct *tsk) - free_thread_info(tsk->stack); - rt_mutex_debug_task_free(tsk); - ftrace_graph_exit_task(tsk); -+ if (task_utrace_struct(tsk)) -+ utrace_free_task(tsk); - free_task_struct(tsk); - } - EXPORT_SYMBOL(free_task); -@@ -1115,6 +1118,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, - if (!p) - goto fork_out; - -+ utrace_init_task(p); -+ - ftrace_graph_init_task(p); - - rt_mutex_init_task(p); -@@ -1583,6 +1583,8 @@ long do_fork(unsigned long clone_flags, - get_task_struct(p); - } - -+ UTRACE_HOOK(current, CLONE, report_clone(clone_flags, p)); -+ - wake_up_new_task(p); - - /* forking complete and child started to run, tell ptracer */ -@@ -1561,6 +1568,8 @@ long do_fork(unsigned long clone_flags, - wake_up_new_task(p); - - /* forking complete and child started to run, tell ptracer */ -+ if (clone_flags & CLONE_VFORK) -+ UTRACE_HOOK(current, CLONE, finish_vfork(current)); - if (unlikely(trace)) - ptrace_event(trace, nr); - -diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 00ab2ca..a7024b8 100644 ---- a/kernel/ptrace.c -+++ b/kernel/ptrace.c -@@ -24,7 +24,34 @@ - #include - #include - #include -+#include - -+void ptrace_signal_wake_up(struct task_struct *p, int quiescent) -+{ -+ unsigned int state; -+ -+ set_tsk_thread_flag(p, TIF_SIGPENDING); -+ -+ state = TASK_INTERRUPTIBLE; -+ if (quiescent) -+ state |= (__TASK_STOPPED | __TASK_TRACED); -+ if (!wake_up_quiescent(p, state)) -+ kick_process(p); -+} -+ -+static void ptrace_set_syscall_trace(struct task_struct *p, bool on) -+{ -+ task_utrace_lock(p); -+ if (on) { -+ p->ptrace |= PT_SYSCALL_TRACE; -+ set_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+ } else { -+ p->ptrace &= ~PT_SYSCALL_TRACE; -+ if (!(task_utrace_flags(p) & UTRACE_EVENT_SYSCALL)) -+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -+ } -+ task_utrace_unlock(p); -+} - - static int ptrace_trapping_sleep_fn(void *flags) - { -@@ -117,7 +144,7 @@ void __ptrace_unlink(struct task_struct *child) - * TASK_KILLABLE sleeps. - */ - if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) -- signal_wake_up(child, task_is_traced(child)); -+ ptrace_signal_wake_up(child, task_is_traced(child)); - - spin_unlock(&child->sighand->siglock); - } -@@ -315,7 +342,7 @@ static int ptrace_attach(struct task_struct *task, long request, - */ - if (task_is_stopped(task) && - task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) -- signal_wake_up(task, 1); -+ ptrace_signal_wake_up(task, 1); - - spin_unlock(&task->sighand->siglock); - -@@ -425,7 +452,7 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) - - /* Architecture-specific hardware disable .. */ - ptrace_disable(child); -- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -+ ptrace_set_syscall_trace(child, false); - - write_lock_irq(&tasklist_lock); - /* -@@ -608,13 +635,12 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) - static int ptrace_resume(struct task_struct *child, long request, - unsigned long data) - { -+ unsigned long flags; -+ - if (!valid_signal(data)) - return -EIO; - -- if (request == PTRACE_SYSCALL) -- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -- else -- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -+ ptrace_set_syscall_trace(child, request == PTRACE_SYSCALL); - - #ifdef TIF_SYSCALL_EMU - if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) -@@ -623,20 +649,23 @@ static int ptrace_resume(struct task_struct *child, long request, - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); - #endif - -+ child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK); - if (is_singleblock(request)) { - if (unlikely(!arch_has_block_step())) - return -EIO; -- user_enable_block_step(child); -+ child->ptrace |= PT_SINGLE_BLOCK; - } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { - if (unlikely(!arch_has_single_step())) - return -EIO; -- user_enable_single_step(child); -- } else { -- user_disable_single_step(child); -+ child->ptrace |= PT_SINGLE_STEP; - } - - child->exit_code = data; -- wake_up_state(child, __TASK_TRACED); -+ -+ if (lock_task_sighand(child, &flags)) { -+ wake_up_quiescent(child, __TASK_TRACED); -+ unlock_task_sighand(child, &flags); -+ } - - return 0; - } -@@ -744,7 +773,7 @@ int ptrace_request(struct task_struct *child, long request, - * tracee into STOP. - */ - if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) -- signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); -+ ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); - - unlock_task_sighand(child, &flags); - ret = 0; -@@ -770,7 +799,7 @@ int ptrace_request(struct task_struct *child, long request, - * start of this trap and now. Trigger re-trap. - */ - if (child->jobctl & JOBCTL_TRAP_NOTIFY) -- signal_wake_up(child, true); -+ ptrace_signal_wake_up(child, true); - ret = 0; - } - unlock_task_sighand(child, &flags); -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index 5255c9d..f1719b8 100644 ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -1167,7 +1167,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) - * is actually now running somewhere else! - */ - while (task_running(rq, p)) { -- if (match_state && unlikely(p->state != match_state)) -+ if (match_state && !likely(p->state & match_state)) - return 0; - cpu_relax(); - } -diff --git a/kernel/signal.c b/kernel/signal.c -index c73c428..0508d93 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -88,7 +88,7 @@ static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns) - /* - * Tracers may want to know about even ignored signals. - */ -- return !t->ptrace; -+ return !t->ptrace && !UTRACE_FLAG(t, SIGNAL_IGN); - } - - /* -@@ -151,6 +151,11 @@ void recalc_sigpending_and_wake(struct task_struct *t) - - void recalc_sigpending(void) - { -+ if (task_utrace_flags(current) && utrace_interrupt_pending()) { -+ set_thread_flag(TIF_SIGPENDING); -+ return; -+ } -+ - if (!recalc_sigpending_tsk(current) && !freezing(current)) - clear_thread_flag(TIF_SIGPENDING); - -@@ -495,7 +500,7 @@ int unhandled_signal(struct task_struct *tsk, int sig) - if (handler != SIG_IGN && handler != SIG_DFL) - return 0; - /* if ptraced, let the tracer determine */ -- return !tsk->ptrace; -+ return !tracehook_consider_fatal_signal(tsk, sig); - } - - /* -@@ -697,6 +702,29 @@ void signal_wake_up(struct task_struct *t, int resume) - kick_process(t); - } - -+#define STATE_QUIESCENT (__TASK_STOPPED | __TASK_TRACED | __TASK_UTRACED) -+/* -+ * wakes up the STOPPED/TRACED task, must be called with ->siglock held. -+ */ -+int wake_up_quiescent(struct task_struct *p, unsigned int state) -+{ -+ unsigned int quiescent = (p->state & STATE_QUIESCENT); -+ -+ WARN_ON(state & ~(STATE_QUIESCENT | TASK_INTERRUPTIBLE)); -+ -+ if (quiescent) { -+ state &= ~TASK_INTERRUPTIBLE; -+ if ((quiescent & ~state) != 0) { -+ p->state &= ~state; -+ WARN_ON(!(p->state & STATE_QUIESCENT)); -+ WARN_ON(!(p->state & TASK_WAKEKILL)); -+ return 0; -+ } -+ } -+ -+ return wake_up_state(p, state); -+} -+ - /* - * Remove signals in mask from the pending set and queue. - * Returns 1 if any signals were found. -@@ -842,7 +870,7 @@ static void ptrace_trap_notify(struct task_struct *t) - assert_spin_locked(&t->sighand->siglock); - - task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY); -- signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); -+ ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); - } - - /* -@@ -884,7 +912,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) - task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING); - rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); - if (likely(!(t->ptrace & PT_SEIZED))) -- wake_up_state(t, __TASK_STOPPED); -+ wake_up_quiescent(t, __TASK_STOPPED); - else - ptrace_trap_notify(t); - } while_each_thread(p, t); -@@ -983,7 +1011,7 @@ static void complete_signal(int sig, struct task_struct *p, int group) - if (sig_fatal(p, sig) && - !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && - !sigismember(&t->real_blocked, sig) && -- (sig == SIGKILL || !t->ptrace)) { -+ (sig == SIGKILL || !tracehook_consider_fatal_signal(t, sig))) { - /* - * This signal will be fatal to the whole group. - */ -@@ -1913,10 +1941,34 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - if (gstop_done) - do_notify_parent_cldstop(current, false, why); - -- __set_current_state(TASK_RUNNING); -+ spin_lock_irq(¤t->sighand->siglock); -+ wake_up_quiescent(current, __TASK_TRACED); -+ spin_unlock_irq(¤t->sighand->siglock); -+ - if (clear_code) - current->exit_code = 0; - read_unlock(&tasklist_lock); -+ -+ /* -+ * It is possible that __TASK_UTRACED was added by utrace -+ * while we were __TASK_TRACED and before we take ->siglock -+ * for wake_up_quiescent(), we need to block in this case. -+ * Otherwise this is unnecessary but absolutely harmless. -+ */ -+ schedule(); -+ } -+ -+ utrace_end_stop(); -+ -+ if (current->ptrace & PT_SINGLE_BLOCK) -+ user_enable_block_step(current); -+ else if (current->ptrace & PT_SINGLE_STEP) -+ user_enable_single_step(current); -+ else { -+ user_disable_single_step(current); -+ /* if utrace needs the stepping it should reassert */ -+ if (task_utrace_flags(current)) -+ set_thread_flag(TIF_NOTIFY_RESUME); - } - - /* -@@ -2081,6 +2133,9 @@ static bool do_signal_stop(int signr) - - /* Now we don't run again until woken by SIGCONT or SIGKILL */ - schedule(); -+ -+ utrace_end_stop(); -+ - return true; - } else { - /* -@@ -2231,17 +2286,27 @@ relock: - for (;;) { - struct k_sigaction *ka; - -- if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && -- do_signal_stop(0)) -+ signr = utrace_hook_signal(current, regs, info, return_ka); -+ if (unlikely(signr < 0)) - goto relock; - -- if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { -- do_jobctl_trap(); -- spin_unlock_irq(&sighand->siglock); -- goto relock; -- } -+ if (unlikely(signr != 0)) -+ ka = return_ka; -+ else { -+ if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && -+ do_signal_stop(0)) -+ goto relock; -+ -+ if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { -+ do_jobctl_trap(); -+ spin_unlock_irq(&sighand->siglock); -+ goto relock; -+ } - -- signr = dequeue_signal(current, ¤t->blocked, info); -+ signr = dequeue_signal(current, ¤t->blocked, info); -+ -+ ka = &sighand->action[signr-1]; -+ } - - if (!signr) - break; /* will return 0 */ -@@ -2251,9 +2316,9 @@ relock: - regs, cookie); - if (!signr) - continue; -- } - -- ka = &sighand->action[signr-1]; -+ ka = &sighand->action[signr-1]; -+ } - - /* Trace actually delivered signals. */ - trace_signal_deliver(signr, info, ka); -diff --git a/kernel/utrace.c b/kernel/utrace.c -new file mode 100644 -index 0000000..a169e1b ---- /dev/null -+++ b/kernel/utrace.c -@@ -0,0 +1,2466 @@ -+/* -+ * utrace infrastructure interface for debugging user processes -+ * -+ * Copyright (C) 2006-2010 Red Hat, Inc. All rights reserved. -+ * -+ * This copyrighted material is made available to anyone wishing to use, -+ * modify, copy, or redistribute it subject to the terms and conditions -+ * of the GNU General Public License v.2. -+ * -+ * Red Hat Author: Roland McGrath. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+/* -+ * Per-thread structure private to utrace implementation. -+ * If task_struct.utrace_flags is nonzero, task_struct.utrace -+ * has always been allocated first. Once allocated, it is -+ * never freed until free_task(). -+ * -+ * The common event reporting loops are done by the task making the -+ * report without ever taking any locks. To facilitate this, the two -+ * lists @attached and @attaching work together for smooth asynchronous -+ * attaching with low overhead. Modifying either list requires @lock. -+ * The @attaching list can be modified any time while holding @lock. -+ * New engines being attached always go on this list. -+ * -+ * The @attached list is what the task itself uses for its reporting -+ * loops. When the task itself is not quiescent, it can use the -+ * @attached list without taking any lock. Nobody may modify the list -+ * when the task is not quiescent. When it is quiescent, that means -+ * that it won't run again without taking @lock itself before using -+ * the list. -+ * -+ * At each place where we know the task is quiescent (or it's current), -+ * while holding @lock, we call splice_attaching(), below. This moves -+ * the @attaching list members on to the end of the @attached list. -+ * Since this happens at the start of any reporting pass, any new -+ * engines attached asynchronously go on the stable @attached list -+ * in time to have their callbacks seen. -+ */ -+struct utrace { -+ spinlock_t lock; -+ struct list_head attached, attaching; -+ -+ struct task_struct *cloning; -+ -+ struct utrace_engine *reporting; -+ -+ enum utrace_resume_action resume:UTRACE_RESUME_BITS; -+ unsigned int signal_handler:1; -+ unsigned int vfork_stop:1; /* need utrace_stop() before vfork wait */ -+ unsigned int death:1; /* in utrace_report_death() now */ -+ unsigned int reap:1; /* release_task() has run */ -+ unsigned int pending_attach:1; /* need splice_attaching() */ -+}; -+ -+static struct kmem_cache *utrace_cachep; -+static struct kmem_cache *utrace_engine_cachep; -+static const struct utrace_engine_ops utrace_detached_ops; /* forward decl */ -+ -+static int __init utrace_init(void) -+{ -+ utrace_cachep = KMEM_CACHE(utrace, SLAB_PANIC); -+ utrace_engine_cachep = KMEM_CACHE(utrace_engine, SLAB_PANIC); -+ return 0; -+} -+module_init(utrace_init); -+ -+void task_utrace_lock(struct task_struct *task) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (!utrace) { -+ task_lock(task); -+ utrace = task_utrace_struct(task); -+ if (!utrace) -+ return; -+ -+ task_unlock(task); -+ } -+ -+ spin_lock(&utrace->lock); -+} -+ -+void task_utrace_unlock(struct task_struct *task) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (utrace) -+ spin_unlock(&utrace->lock); -+ else -+ task_unlock(task); -+} -+ -+/* -+ * Set up @task.utrace for the first time. We can have races -+ * between two utrace_attach_task() calls here. The task_lock() -+ * governs installing the new pointer. If another one got in first, -+ * we just punt the new one we allocated. -+ * -+ * This returns false only in case of a memory allocation failure. -+ */ -+static bool utrace_task_alloc(struct task_struct *task, gfp_t gfp_flags) -+{ -+ struct utrace *utrace = kmem_cache_zalloc(utrace_cachep, gfp_flags); -+ if (unlikely(!utrace)) -+ return false; -+ spin_lock_init(&utrace->lock); -+ INIT_LIST_HEAD(&utrace->attached); -+ INIT_LIST_HEAD(&utrace->attaching); -+ utrace->resume = UTRACE_RESUME; -+ task_lock(task); -+ if (likely(!task->utrace)) { -+ /* -+ * This barrier makes sure the initialization of the struct -+ * precedes the installation of the pointer. This pairs -+ * with smp_read_barrier_depends() in task_utrace_struct(). -+ */ -+ smp_wmb(); -+ task->utrace = utrace; -+ } -+ task_unlock(task); -+ -+ if (unlikely(task->utrace != utrace)) -+ kmem_cache_free(utrace_cachep, utrace); -+ return true; -+} -+ -+/* -+ * This is called via tracehook_free_task() from free_task() -+ * when @task is being deallocated. -+ */ -+void utrace_free_task(struct task_struct *task) -+{ -+ kmem_cache_free(utrace_cachep, task->utrace); -+} -+ -+/* -+ * This is calledwhen the task is safely quiescent, i.e. it won't consult -+ * utrace->attached without the lock. Move any engines attached -+ * asynchronously from @utrace->attaching onto the @utrace->attached list. -+ */ -+static void splice_attaching(struct utrace *utrace) -+{ -+ lockdep_assert_held(&utrace->lock); -+ list_splice_tail_init(&utrace->attaching, &utrace->attached); -+ utrace->pending_attach = 0; -+} -+ -+/* -+ * This is the exported function used by the utrace_engine_put() inline. -+ */ -+void __utrace_engine_release(struct kref *kref) -+{ -+ struct utrace_engine *engine = container_of(kref, struct utrace_engine, -+ kref); -+ BUG_ON(!list_empty(&engine->entry)); -+ if (engine->release) -+ (*engine->release)(engine->data); -+ kmem_cache_free(utrace_engine_cachep, engine); -+} -+EXPORT_SYMBOL_GPL(__utrace_engine_release); -+ -+static bool engine_matches(struct utrace_engine *engine, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ if ((flags & UTRACE_ATTACH_MATCH_OPS) && engine->ops != ops) -+ return false; -+ if ((flags & UTRACE_ATTACH_MATCH_DATA) && engine->data != data) -+ return false; -+ return engine->ops && engine->ops != &utrace_detached_ops; -+} -+ -+static struct utrace_engine *find_matching_engine( -+ struct utrace *utrace, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace_engine *engine; -+ list_for_each_entry(engine, &utrace->attached, entry) -+ if (engine_matches(engine, flags, ops, data)) -+ return engine; -+ list_for_each_entry(engine, &utrace->attaching, entry) -+ if (engine_matches(engine, flags, ops, data)) -+ return engine; -+ return NULL; -+} -+ -+/* -+ * Enqueue @engine, or maybe don't if UTRACE_ATTACH_EXCLUSIVE. -+ */ -+static int utrace_add_engine(struct task_struct *target, -+ struct utrace *utrace, -+ struct utrace_engine *engine, -+ int flags, -+ const struct utrace_engine_ops *ops, -+ void *data) -+{ -+ int ret; -+ -+ spin_lock(&utrace->lock); -+ -+ ret = -EEXIST; -+ if ((flags & UTRACE_ATTACH_EXCLUSIVE) && -+ unlikely(find_matching_engine(utrace, flags, ops, data))) -+ goto unlock; -+ -+ /* -+ * In case we had no engines before, make sure that -+ * utrace_flags is not zero. Since we did unlock+lock -+ * at least once after utrace_task_alloc() installed -+ * ->utrace, we have the necessary barrier which pairs -+ * with rmb() in task_utrace_struct(). -+ */ -+ ret = -ESRCH; -+ if (!target->utrace_flags) { -+ target->utrace_flags = UTRACE_EVENT(REAP); -+ /* -+ * If we race with tracehook_prepare_release_task() -+ * make sure that either it sees utrace_flags != 0 -+ * or we see exit_state == EXIT_DEAD. -+ */ -+ smp_mb(); -+ if (unlikely(target->exit_state == EXIT_DEAD)) { -+ target->utrace_flags = 0; -+ goto unlock; -+ } -+ } -+ -+ /* -+ * Put the new engine on the pending ->attaching list. -+ * Make sure it gets onto the ->attached list by the next -+ * time it's examined. Setting ->pending_attach ensures -+ * that start_report() takes the lock and splices the lists -+ * before the next new reporting pass. -+ * -+ * When target == current, it would be safe just to call -+ * splice_attaching() right here. But if we're inside a -+ * callback, that would mean the new engine also gets -+ * notified about the event that precipitated its own -+ * creation. This is not what the user wants. -+ */ -+ list_add_tail(&engine->entry, &utrace->attaching); -+ utrace->pending_attach = 1; -+ utrace_engine_get(engine); -+ ret = 0; -+unlock: -+ spin_unlock(&utrace->lock); -+ -+ return ret; -+} -+ -+/** -+ * utrace_attach_task - attach new engine, or look up an attached engine -+ * @target: thread to attach to -+ * @flags: flag bits combined with OR, see below -+ * @ops: callback table for new engine -+ * @data: engine private data pointer -+ * -+ * The caller must ensure that the @target thread does not get freed, -+ * i.e. hold a ref or be its parent. It is always safe to call this -+ * on @current, or on the @child pointer in a @report_clone callback. -+ * For most other cases, it's easier to use utrace_attach_pid() instead. -+ * -+ * UTRACE_ATTACH_CREATE: -+ * Create a new engine. If %UTRACE_ATTACH_CREATE is not specified, you -+ * only look up an existing engine already attached to the thread. -+ * -+ * UTRACE_ATTACH_EXCLUSIVE: -+ * Attempting to attach a second (matching) engine fails with -%EEXIST. -+ * -+ * UTRACE_ATTACH_MATCH_OPS: Only consider engines matching @ops. -+ * UTRACE_ATTACH_MATCH_DATA: Only consider engines matching @data. -+ * -+ * Calls with neither %UTRACE_ATTACH_MATCH_OPS nor %UTRACE_ATTACH_MATCH_DATA -+ * match the first among any engines attached to @target. That means that -+ * %UTRACE_ATTACH_EXCLUSIVE in such a call fails with -%EEXIST if there -+ * are any engines on @target at all. -+ */ -+struct utrace_engine *utrace_attach_task( -+ struct task_struct *target, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace *utrace = task_utrace_struct(target); -+ struct utrace_engine *engine; -+ gfp_t gfp_flags; -+ int ret; -+ -+ if (!(flags & UTRACE_ATTACH_CREATE)) { -+ if (unlikely(!utrace)) -+ return ERR_PTR(-ENOENT); -+ spin_lock(&utrace->lock); -+ engine = find_matching_engine(utrace, flags, ops, data); -+ if (engine) -+ utrace_engine_get(engine); -+ spin_unlock(&utrace->lock); -+ return engine ?: ERR_PTR(-ENOENT); -+ } -+ -+ if (unlikely(!ops) || unlikely(ops == &utrace_detached_ops)) -+ return ERR_PTR(-EINVAL); -+ -+ if (unlikely(target->flags & PF_KTHREAD)) -+ /* -+ * Silly kernel, utrace is for users! -+ */ -+ return ERR_PTR(-EPERM); -+ -+ gfp_flags = (flags & UTRACE_ATTACH_ATOMIC) -+ ? GFP_ATOMIC : GFP_KERNEL; -+ -+ if (!utrace) { -+ if (unlikely(!utrace_task_alloc(target, gfp_flags))) -+ return ERR_PTR(-ENOMEM); -+ utrace = task_utrace_struct(target); -+ } -+ -+ engine = kmem_cache_alloc(utrace_engine_cachep, gfp_flags); -+ if (unlikely(!engine)) -+ return ERR_PTR(-ENOMEM); -+ -+ /* -+ * Initialize the new engine structure. It starts out with one ref -+ * to return. utrace_add_engine() adds another for being attached. -+ */ -+ kref_init(&engine->kref); -+ engine->flags = 0; -+ engine->ops = ops; -+ engine->data = data; -+ engine->release = ops->release; -+ -+ ret = utrace_add_engine(target, utrace, engine, flags, ops, data); -+ -+ if (unlikely(ret)) { -+ kmem_cache_free(utrace_engine_cachep, engine); -+ engine = ERR_PTR(ret); -+ } -+ -+ -+ return engine; -+} -+EXPORT_SYMBOL_GPL(utrace_attach_task); -+ -+/** -+ * utrace_attach_pid - attach new engine, or look up an attached engine -+ * @pid: &struct pid pointer representing thread to attach to -+ * @flags: flag bits combined with OR, see utrace_attach_task() -+ * @ops: callback table for new engine -+ * @data: engine private data pointer -+ * -+ * This is the same as utrace_attach_task(), but takes a &struct pid -+ * pointer rather than a &struct task_struct pointer. The caller must -+ * hold a ref on @pid, but does not need to worry about the task -+ * staying valid. If it's been reaped so that @pid points nowhere, -+ * then this call returns -%ESRCH. -+ */ -+struct utrace_engine *utrace_attach_pid( -+ struct pid *pid, int flags, -+ const struct utrace_engine_ops *ops, void *data) -+{ -+ struct utrace_engine *engine = ERR_PTR(-ESRCH); -+ struct task_struct *task = get_pid_task(pid, PIDTYPE_PID); -+ if (task) { -+ engine = utrace_attach_task(task, flags, ops, data); -+ put_task_struct(task); -+ } -+ return engine; -+} -+EXPORT_SYMBOL_GPL(utrace_attach_pid); -+ -+/* -+ * When an engine is detached, the target thread may still see it and -+ * make callbacks until it quiesces. We install a special ops vector -+ * with these two callbacks. When the target thread quiesces, it can -+ * safely free the engine itself. For any event we will always get -+ * the report_quiesce() callback first, so we only need this one -+ * pointer to be set. The only exception is report_reap(), so we -+ * supply that callback too. -+ */ -+static u32 utrace_detached_quiesce(u32 action, struct utrace_engine *engine, -+ unsigned long event) -+{ -+ return UTRACE_DETACH; -+} -+ -+static void utrace_detached_reap(struct utrace_engine *engine, -+ struct task_struct *task) -+{ -+} -+ -+static const struct utrace_engine_ops utrace_detached_ops = { -+ .report_quiesce = &utrace_detached_quiesce, -+ .report_reap = &utrace_detached_reap -+}; -+ -+/* -+ * The caller has to hold a ref on the engine. If the attached flag is -+ * true (all but utrace_barrier() calls), the engine is supposed to be -+ * attached. If the attached flag is false (utrace_barrier() only), -+ * then return -ERESTARTSYS for an engine marked for detach but not yet -+ * fully detached. The task pointer can be invalid if the engine is -+ * detached. -+ * -+ * Get the utrace lock for the target task. -+ * Returns the struct if locked, or ERR_PTR(-errno). -+ * -+ * This has to be robust against races with: -+ * utrace_control(target, UTRACE_DETACH) calls -+ * UTRACE_DETACH after reports -+ * utrace_report_death -+ * utrace_release_task -+ */ -+static struct utrace *get_utrace_lock(struct task_struct *target, -+ struct utrace_engine *engine, -+ bool attached) -+ __acquires(utrace->lock) -+{ -+ struct utrace *utrace; -+ -+ rcu_read_lock(); -+ -+ /* -+ * If this engine was already detached, bail out before we look at -+ * the task_struct pointer at all. If it's detached after this -+ * check, then RCU is still keeping this task_struct pointer valid. -+ * -+ * The ops pointer is NULL when the engine is fully detached. -+ * It's &utrace_detached_ops when it's marked detached but still -+ * on the list. In the latter case, utrace_barrier() still works, -+ * since the target might be in the middle of an old callback. -+ */ -+ if (unlikely(!engine->ops)) { -+ rcu_read_unlock(); -+ return ERR_PTR(-ESRCH); -+ } -+ -+ if (unlikely(engine->ops == &utrace_detached_ops)) { -+ rcu_read_unlock(); -+ return attached ? ERR_PTR(-ESRCH) : ERR_PTR(-ERESTARTSYS); -+ } -+ -+ utrace = task_utrace_struct(target); -+ spin_lock(&utrace->lock); -+ if (unlikely(utrace->reap) || unlikely(!engine->ops) || -+ unlikely(engine->ops == &utrace_detached_ops)) { -+ /* -+ * By the time we got the utrace lock, -+ * it had been reaped or detached already. -+ */ -+ spin_unlock(&utrace->lock); -+ utrace = ERR_PTR(-ESRCH); -+ if (!attached && engine->ops == &utrace_detached_ops) -+ utrace = ERR_PTR(-ERESTARTSYS); -+ } -+ rcu_read_unlock(); -+ -+ return utrace; -+} -+ -+/* -+ * Now that we don't hold any locks, run through any -+ * detached engines and free their references. Each -+ * engine had one implicit ref while it was attached. -+ */ -+static void put_detached_list(struct list_head *list) -+{ -+ struct utrace_engine *engine, *next; -+ list_for_each_entry_safe(engine, next, list, entry) { -+ list_del_init(&engine->entry); -+ utrace_engine_put(engine); -+ } -+} -+ -+/* -+ * We use an extra bit in utrace_engine.flags past the event bits, -+ * to record whether the engine is keeping the target thread stopped. -+ * -+ * This bit is set in task_struct.utrace_flags whenever it is set in any -+ * engine's flags. Only utrace_reset() resets it in utrace_flags. -+ */ -+#define ENGINE_STOP (1UL << _UTRACE_NEVENTS) -+ -+#define task_is_utraced(task) ((task->state & __TASK_UTRACED) != 0) -+ -+static void mark_engine_wants_stop(struct task_struct *task, -+ struct utrace_engine *engine) -+{ -+ engine->flags |= ENGINE_STOP; -+ task->utrace_flags |= ENGINE_STOP; -+} -+ -+static void clear_engine_wants_stop(struct utrace_engine *engine) -+{ -+ engine->flags &= ~ENGINE_STOP; -+} -+ -+static bool engine_wants_stop(struct utrace_engine *engine) -+{ -+ return (engine->flags & ENGINE_STOP) != 0; -+} -+ -+/** -+ * utrace_set_events - choose which event reports a tracing engine gets -+ * @target: thread to affect -+ * @engine: attached engine to affect -+ * @events: new event mask -+ * -+ * This changes the set of events for which @engine wants callbacks made. -+ * -+ * This fails with -%EALREADY and does nothing if you try to clear -+ * %UTRACE_EVENT(%DEATH) when the @report_death callback may already have -+ * begun, or if you try to newly set %UTRACE_EVENT(%DEATH) or -+ * %UTRACE_EVENT(%QUIESCE) when @target is already dead or dying. -+ * -+ * This fails with -%ESRCH if you try to clear %UTRACE_EVENT(%REAP) when -+ * the @report_reap callback may already have begun, or when @target has -+ * already been detached, including forcible detach on reaping. -+ * -+ * If @target was stopped before the call, then after a successful call, -+ * no event callbacks not requested in @events will be made; if -+ * %UTRACE_EVENT(%QUIESCE) is included in @events, then a -+ * @report_quiesce callback will be made when @target resumes. -+ * -+ * If @target was not stopped and @events excludes some bits that were -+ * set before, this can return -%EINPROGRESS to indicate that @target -+ * may have been making some callback to @engine. When this returns -+ * zero, you can be sure that no event callbacks you've disabled in -+ * @events can be made. If @events only sets new bits that were not set -+ * before on @engine, then -%EINPROGRESS will never be returned. -+ * -+ * To synchronize after an -%EINPROGRESS return, see utrace_barrier(). -+ * -+ * When @target is @current, -%EINPROGRESS is not returned. But note -+ * that a newly-created engine will not receive any callbacks related to -+ * an event notification already in progress. This call enables @events -+ * callbacks to be made as soon as @engine becomes eligible for any -+ * callbacks, see utrace_attach_task(). -+ * -+ * These rules provide for coherent synchronization based on %UTRACE_STOP, -+ * even when %SIGKILL is breaking its normal simple rules. -+ */ -+int utrace_set_events(struct task_struct *target, -+ struct utrace_engine *engine, -+ unsigned long events) -+{ -+ struct utrace *utrace; -+ unsigned long old_flags, old_utrace_flags; -+ int ret = -EALREADY; -+ -+ /* -+ * We just ignore the internal bit, so callers can use -+ * engine->flags to seed bitwise ops for our argument. -+ */ -+ events &= ~ENGINE_STOP; -+ -+ utrace = get_utrace_lock(target, engine, true); -+ if (unlikely(IS_ERR(utrace))) -+ return PTR_ERR(utrace); -+ -+ old_utrace_flags = target->utrace_flags; -+ old_flags = engine->flags & ~ENGINE_STOP; -+ -+ /* -+ * If utrace_report_death() is already progress now, -+ * it's too late to clear the death event bits. -+ */ -+ if (((old_flags & ~events) & _UTRACE_DEATH_EVENTS) && utrace->death) -+ goto unlock; -+ -+ /* -+ * When setting these flags, it's essential that we really -+ * synchronize with exit_notify(). They cannot be set after -+ * exit_notify() takes the tasklist_lock. By holding the read -+ * lock here while setting the flags, we ensure that the calls -+ * to tracehook_notify_death() and tracehook_report_death() will -+ * see the new flags. This ensures that utrace_release_task() -+ * knows positively that utrace_report_death() will be called or -+ * that it won't. -+ */ -+ if ((events & ~old_flags) & _UTRACE_DEATH_EVENTS) { -+ read_lock(&tasklist_lock); -+ if (unlikely(target->exit_state)) { -+ read_unlock(&tasklist_lock); -+ goto unlock; -+ } -+ target->utrace_flags |= events; -+ read_unlock(&tasklist_lock); -+ } -+ -+ engine->flags = events | (engine->flags & ENGINE_STOP); -+ target->utrace_flags |= events; -+ -+ if ((events & UTRACE_EVENT_SYSCALL) && -+ !(old_utrace_flags & UTRACE_EVENT_SYSCALL)) -+ set_tsk_thread_flag(target, TIF_SYSCALL_TRACE); -+ -+ ret = 0; -+ if ((old_flags & ~events) && target != current && -+ !task_is_utraced(target) && !target->exit_state) { -+ /* -+ * This barrier ensures that our engine->flags changes -+ * have hit before we examine utrace->reporting, -+ * pairing with the barrier in start_callback(). If -+ * @target has not yet hit finish_callback() to clear -+ * utrace->reporting, we might be in the middle of a -+ * callback to @engine. -+ */ -+ smp_mb(); -+ if (utrace->reporting == engine) -+ ret = -EINPROGRESS; -+ } -+unlock: -+ spin_unlock(&utrace->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_set_events); -+ -+/* -+ * Asynchronously mark an engine as being detached. -+ * -+ * This must work while the target thread races with us doing -+ * start_callback(), defined below. It uses smp_rmb() between checking -+ * @engine->flags and using @engine->ops. Here we change @engine->ops -+ * first, then use smp_wmb() before changing @engine->flags. This ensures -+ * it can check the old flags before using the old ops, or check the old -+ * flags before using the new ops, or check the new flags before using the -+ * new ops, but can never check the new flags before using the old ops. -+ * Hence, utrace_detached_ops might be used with any old flags in place. -+ * It has report_quiesce() and report_reap() callbacks to handle all cases. -+ */ -+static void mark_engine_detached(struct utrace_engine *engine) -+{ -+ engine->ops = &utrace_detached_ops; -+ smp_wmb(); -+ engine->flags = UTRACE_EVENT(QUIESCE); -+} -+ -+/* -+ * Get @target to stop and return true if it is already stopped now. -+ * If we return false, it will make some event callback soonish. -+ * Called with @utrace locked. -+ */ -+static bool utrace_do_stop(struct task_struct *target, struct utrace *utrace) -+{ -+ if (task_is_stopped_or_traced(target)) { -+ /* -+ * Stopped is considered quiescent; when it wakes up, it will -+ * go through utrace_finish_stop() before doing anything else. -+ */ -+ spin_lock_irq(&target->sighand->siglock); -+ if (likely(task_is_stopped_or_traced(target))) -+ target->state |= TASK_UTRACED; -+ spin_unlock_irq(&target->sighand->siglock); -+ } else if (utrace->resume > UTRACE_REPORT) { -+ utrace->resume = UTRACE_REPORT; -+ set_notify_resume(target); -+ } -+ -+ return task_is_utraced(target); -+} -+ -+/* -+ * If the target is not dead it should not be in tracing -+ * stop any more. Wake it unless it's in job control stop. -+ */ -+static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) -+{ -+ lockdep_assert_held(&utrace->lock); -+ spin_lock_irq(&target->sighand->siglock); -+ wake_up_quiescent(target, __TASK_UTRACED); -+ spin_unlock_irq(&target->sighand->siglock); -+} -+ -+/* -+ * This is called when there might be some detached engines on the list or -+ * some stale bits in @task->utrace_flags. Clean them up and recompute the -+ * flags. Returns true if we're now fully detached. -+ * -+ * Called with @utrace->lock held, returns with it released. -+ * After this returns, @utrace might be freed if everything detached. -+ */ -+static bool utrace_reset(struct task_struct *task, struct utrace *utrace) -+ __releases(utrace->lock) -+{ -+ struct utrace_engine *engine, *next; -+ unsigned long flags = 0; -+ LIST_HEAD(detached); -+ -+ splice_attaching(utrace); -+ -+ /* -+ * Update the set of events of interest from the union -+ * of the interests of the remaining tracing engines. -+ * For any engine marked detached, remove it from the list. -+ * We'll collect them on the detached list. -+ */ -+ list_for_each_entry_safe(engine, next, &utrace->attached, entry) { -+ if (engine->ops == &utrace_detached_ops) { -+ engine->ops = NULL; -+ list_move(&engine->entry, &detached); -+ } else { -+ flags |= engine->flags | UTRACE_EVENT(REAP); -+ } -+ } -+ -+ if (task->exit_state) { -+ /* -+ * Once it's already dead, we never install any flags -+ * except REAP. When ->exit_state is set and events -+ * like DEATH are not set, then they never can be set. -+ * This ensures that utrace_release_task() knows -+ * positively that utrace_report_death() can never run. -+ */ -+ BUG_ON(utrace->death); -+ flags &= UTRACE_EVENT(REAP); -+ } else if (!(flags & UTRACE_EVENT_SYSCALL) && -+ !(task->ptrace & PT_SYSCALL_TRACE) && -+ test_tsk_thread_flag(task, TIF_SYSCALL_TRACE)) { -+ clear_tsk_thread_flag(task, TIF_SYSCALL_TRACE); -+ } -+ -+ if (!flags) { -+ /* -+ * No more engines, cleared out the utrace. -+ */ -+ utrace->resume = UTRACE_RESUME; -+ utrace->signal_handler = 0; -+ } -+ -+ /* -+ * If no more engines want it stopped, wake it up. -+ */ -+ if (task_is_utraced(task) && !(flags & ENGINE_STOP)) { -+ /* -+ * It just resumes, so make sure single-step -+ * is not left set. -+ */ -+ if (utrace->resume == UTRACE_RESUME) -+ user_disable_single_step(task); -+ utrace_wakeup(task, utrace); -+ } -+ -+ /* -+ * In theory spin_lock() doesn't imply rcu_read_lock(). -+ * Once we clear ->utrace_flags this task_struct can go away -+ * because tracehook_prepare_release_task() path does not take -+ * utrace->lock when ->utrace_flags == 0. -+ */ -+ rcu_read_lock(); -+ task->utrace_flags = flags; -+ spin_unlock(&utrace->lock); -+ rcu_read_unlock(); -+ -+ put_detached_list(&detached); -+ -+ return !flags; -+} -+ -+void utrace_finish_stop(void) -+{ -+ /* -+ * If we were task_is_utraced() and then SIGKILL'ed, make -+ * sure we do nothing until the tracer drops utrace->lock. -+ */ -+ if (unlikely(__fatal_signal_pending(current))) { -+ struct utrace *utrace = task_utrace_struct(current); -+ spin_unlock_wait(&utrace->lock); -+ } -+} -+ -+/* -+ * Perform %UTRACE_STOP, i.e. block in TASK_UTRACED until woken up. -+ * @task == current, @utrace == current->utrace, which is not locked. -+ * Return true if we were woken up by SIGKILL even though some utrace -+ * engine may still want us to stay stopped. -+ */ -+static void utrace_stop(struct task_struct *task, struct utrace *utrace, -+ enum utrace_resume_action action) -+{ -+relock: -+ spin_lock(&utrace->lock); -+ -+ if (action < utrace->resume) { -+ /* -+ * Ensure a reporting pass when we're resumed. -+ */ -+ utrace->resume = action; -+ if (action == UTRACE_INTERRUPT) -+ set_thread_flag(TIF_SIGPENDING); -+ else -+ set_thread_flag(TIF_NOTIFY_RESUME); -+ } -+ -+ /* -+ * If the ENGINE_STOP bit is clear in utrace_flags, that means -+ * utrace_reset() ran after we processed some UTRACE_STOP return -+ * values from callbacks to get here. If all engines have detached -+ * or resumed us, we don't stop. This check doesn't require -+ * siglock, but it should follow the interrupt/report bookkeeping -+ * steps (this can matter for UTRACE_RESUME but not UTRACE_DETACH). -+ */ -+ if (unlikely(!(task->utrace_flags & ENGINE_STOP))) { -+ utrace_reset(task, utrace); -+ if (task->utrace_flags & ENGINE_STOP) -+ goto relock; -+ return; -+ } -+ -+ /* -+ * The siglock protects us against signals. As well as SIGKILL -+ * waking us up, we must synchronize with the signal bookkeeping -+ * for stop signals and SIGCONT. -+ */ -+ spin_lock_irq(&task->sighand->siglock); -+ -+ if (unlikely(__fatal_signal_pending(task))) { -+ spin_unlock_irq(&task->sighand->siglock); -+ spin_unlock(&utrace->lock); -+ return; -+ } -+ -+ __set_current_state(TASK_UTRACED); -+ -+ spin_unlock_irq(&task->sighand->siglock); -+ spin_unlock(&utrace->lock); -+ -+ schedule(); -+ -+ utrace_finish_stop(); -+ -+ /* -+ * While in TASK_UTRACED, we were considered "frozen enough". -+ * Now that we woke up, it's crucial if we're supposed to be -+ * frozen that we freeze now before running anything substantial. -+ */ -+ try_to_freeze(); -+ -+ /* -+ * While we were in TASK_UTRACED, complete_signal() considered -+ * us "uninterested" in signal wakeups. Now make sure our -+ * TIF_SIGPENDING state is correct for normal running. -+ */ -+ spin_lock_irq(&task->sighand->siglock); -+ recalc_sigpending(); -+ spin_unlock_irq(&task->sighand->siglock); -+} -+ -+/* -+ * Called by release_task() with @reap set to true. -+ * Called by utrace_report_death() with @reap set to false. -+ * On reap, make report_reap callbacks and clean out @utrace -+ * unless still making callbacks. On death, update bookkeeping -+ * and handle the reap work if release_task() came in first. -+ */ -+void utrace_maybe_reap(struct task_struct *target, struct utrace *utrace, -+ bool reap) -+{ -+ struct utrace_engine *engine, *next; -+ struct list_head attached; -+ -+ spin_lock(&utrace->lock); -+ -+ if (reap) { -+ /* -+ * If the target will do some final callbacks but hasn't -+ * finished them yet, we know because it clears these event -+ * bits after it's done. Instead of cleaning up here and -+ * requiring utrace_report_death() to cope with it, we -+ * delay the REAP report and the teardown until after the -+ * target finishes its death reports. -+ */ -+ utrace->reap = 1; -+ -+ if (target->utrace_flags & _UTRACE_DEATH_EVENTS) { -+ spin_unlock(&utrace->lock); -+ return; -+ } -+ } else { -+ /* -+ * After we unlock with this flag clear, any competing -+ * utrace_control/utrace_set_events calls know that we've -+ * finished our callbacks and any detach bookkeeping. -+ */ -+ utrace->death = 0; -+ -+ if (!utrace->reap) { -+ /* -+ * We're just dead, not reaped yet. This will -+ * reset @target->utrace_flags so the later call -+ * with @reap set won't hit the check above. -+ */ -+ utrace_reset(target, utrace); -+ return; -+ } -+ } -+ -+ /* -+ * utrace_add_engine() checks ->utrace_flags != 0. Since -+ * @utrace->reap is set, nobody can set or clear UTRACE_EVENT(REAP) -+ * in @engine->flags or change @engine->ops and nobody can change -+ * @utrace->attached after we drop the lock. -+ */ -+ target->utrace_flags = 0; -+ -+ /* -+ * We clear out @utrace->attached before we drop the lock so -+ * that find_matching_engine() can't come across any old engine -+ * while we are busy tearing it down. -+ */ -+ list_replace_init(&utrace->attached, &attached); -+ list_splice_tail_init(&utrace->attaching, &attached); -+ -+ spin_unlock(&utrace->lock); -+ -+ list_for_each_entry_safe(engine, next, &attached, entry) { -+ if (engine->flags & UTRACE_EVENT(REAP)) -+ engine->ops->report_reap(engine, target); -+ -+ engine->ops = NULL; -+ engine->flags = 0; -+ list_del_init(&engine->entry); -+ -+ utrace_engine_put(engine); -+ } -+} -+ -+/* -+ * You can't do anything to a dead task but detach it. -+ * If release_task() has been called, you can't do that. -+ * -+ * On the exit path, DEATH and QUIESCE event bits are set only -+ * before utrace_report_death() has taken the lock. At that point, -+ * the death report will come soon, so disallow detach until it's -+ * done. This prevents us from racing with it detaching itself. -+ * -+ * Called only when @target->exit_state is nonzero. -+ */ -+static inline int utrace_control_dead(struct task_struct *target, -+ struct utrace *utrace, -+ enum utrace_resume_action action) -+{ -+ lockdep_assert_held(&utrace->lock); -+ -+ if (action != UTRACE_DETACH || unlikely(utrace->reap)) -+ return -ESRCH; -+ -+ if (unlikely(utrace->death)) -+ /* -+ * We have already started the death report. We can't -+ * prevent the report_death and report_reap callbacks, -+ * so tell the caller they will happen. -+ */ -+ return -EALREADY; -+ -+ return 0; -+} -+ -+/** -+ * utrace_control - control a thread being traced by a tracing engine -+ * @target: thread to affect -+ * @engine: attached engine to affect -+ * @action: &enum utrace_resume_action for thread to do -+ * -+ * This is how a tracing engine asks a traced thread to do something. -+ * This call is controlled by the @action argument, which has the -+ * same meaning as the &enum utrace_resume_action value returned by -+ * event reporting callbacks. -+ * -+ * If @target is already dead (@target->exit_state nonzero), -+ * all actions except %UTRACE_DETACH fail with -%ESRCH. -+ * -+ * The following sections describe each option for the @action argument. -+ * -+ * UTRACE_DETACH: -+ * -+ * After this, the @engine data structure is no longer accessible, -+ * and the thread might be reaped. The thread will start running -+ * again if it was stopped and no longer has any attached engines -+ * that want it stopped. -+ * -+ * If the @report_reap callback may already have begun, this fails -+ * with -%ESRCH. If the @report_death callback may already have -+ * begun, this fails with -%EALREADY. -+ * -+ * If @target is not already stopped, then a callback to this engine -+ * might be in progress or about to start on another CPU. If so, -+ * then this returns -%EINPROGRESS; the detach happens as soon as -+ * the pending callback is finished. To synchronize after an -+ * -%EINPROGRESS return, see utrace_barrier(). -+ * -+ * If @target is properly stopped before utrace_control() is called, -+ * then after successful return it's guaranteed that no more callbacks -+ * to the @engine->ops vector will be made. -+ * -+ * The only exception is %SIGKILL (and exec or group-exit by another -+ * thread in the group), which can cause asynchronous @report_death -+ * and/or @report_reap callbacks even when %UTRACE_STOP was used. -+ * (In that event, this fails with -%ESRCH or -%EALREADY, see above.) -+ * -+ * UTRACE_STOP: -+ * -+ * This asks that @target stop running. This returns 0 only if -+ * @target is already stopped, either for tracing or for job -+ * control. Then @target will remain stopped until another -+ * utrace_control() call is made on @engine; @target can be woken -+ * only by %SIGKILL (or equivalent, such as exec or termination by -+ * another thread in the same thread group). -+ * -+ * This returns -%EINPROGRESS if @target is not already stopped. -+ * Then the effect is like %UTRACE_REPORT. A @report_quiesce or -+ * @report_signal callback will be made soon. Your callback can -+ * then return %UTRACE_STOP to keep @target stopped. -+ * -+ * This does not interrupt system calls in progress, including ones -+ * that sleep for a long time. For that, use %UTRACE_INTERRUPT. -+ * To interrupt system calls and then keep @target stopped, your -+ * @report_signal callback can return %UTRACE_STOP. -+ * -+ * UTRACE_RESUME: -+ * -+ * Just let @target continue running normally, reversing the effect -+ * of a previous %UTRACE_STOP. If another engine is keeping @target -+ * stopped, then it remains stopped until all engines let it resume. -+ * If @target was not stopped, this has no effect. -+ * -+ * UTRACE_REPORT: -+ * -+ * This is like %UTRACE_RESUME, but also ensures that there will be -+ * a @report_quiesce or @report_signal callback made soon. If -+ * @target had been stopped, then there will be a callback before it -+ * resumes running normally. If another engine is keeping @target -+ * stopped, then there might be no callbacks until all engines let -+ * it resume. -+ * -+ * Since this is meaningless unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). -+ * -+ * UTRACE_INTERRUPT: -+ * -+ * This is like %UTRACE_REPORT, but ensures that @target will make a -+ * @report_signal callback before it resumes or delivers signals. -+ * If @target was in a system call or about to enter one, work in -+ * progress will be interrupted as if by %SIGSTOP. If another -+ * engine is keeping @target stopped, then there might be no -+ * callbacks until all engines let it resume. -+ * -+ * This gives @engine an opportunity to introduce a forced signal -+ * disposition via its @report_signal callback. -+ * -+ * UTRACE_SINGLESTEP: -+ * -+ * It's invalid to use this unless arch_has_single_step() returned true. -+ * This is like %UTRACE_RESUME, but resumes for one user instruction only. -+ * -+ * Note that passing %UTRACE_SINGLESTEP or %UTRACE_BLOCKSTEP to -+ * utrace_control() or returning it from an event callback alone does -+ * not necessarily ensure that stepping will be enabled. If there are -+ * more callbacks made to any engine before returning to user mode, -+ * then the resume action is chosen only by the last set of callbacks. -+ * To be sure, enable %UTRACE_EVENT(%QUIESCE) and look for the -+ * @report_quiesce callback with a zero event mask, or the -+ * @report_signal callback with %UTRACE_SIGNAL_REPORT. -+ * -+ * Since this is not robust unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). -+ * -+ * UTRACE_BLOCKSTEP: -+ * -+ * It's invalid to use this unless arch_has_block_step() returned true. -+ * This is like %UTRACE_SINGLESTEP, but resumes for one whole basic -+ * block of user instructions. -+ * -+ * Since this is not robust unless @report_quiesce callbacks will -+ * be made, it returns -%EINVAL if @engine lacks %UTRACE_EVENT(%QUIESCE). -+ * -+ * %UTRACE_BLOCKSTEP devolves to %UTRACE_SINGLESTEP when another -+ * tracing engine is using %UTRACE_SINGLESTEP at the same time. -+ */ -+int utrace_control(struct task_struct *target, -+ struct utrace_engine *engine, -+ enum utrace_resume_action action) -+{ -+ struct utrace *utrace; -+ bool reset; -+ int ret; -+ -+ if (unlikely(action >= UTRACE_RESUME_MAX)) { -+ WARN(1, "invalid action argument to utrace_control()!"); -+ return -EINVAL; -+ } -+ -+ /* -+ * This is a sanity check for a programming error in the caller. -+ * Their request can only work properly in all cases by relying on -+ * a follow-up callback, but they didn't set one up! This check -+ * doesn't do locking, but it shouldn't matter. The caller has to -+ * be synchronously sure the callback is set up to be operating the -+ * interface properly. -+ */ -+ if (action >= UTRACE_REPORT && action < UTRACE_RESUME && -+ unlikely(!(engine->flags & UTRACE_EVENT(QUIESCE)))) { -+ WARN(1, "utrace_control() with no QUIESCE callback in place!"); -+ return -EINVAL; -+ } -+ -+ utrace = get_utrace_lock(target, engine, true); -+ if (unlikely(IS_ERR(utrace))) -+ return PTR_ERR(utrace); -+ -+ reset = task_is_utraced(target); -+ ret = 0; -+ -+ /* -+ * ->exit_state can change under us, this doesn't matter. -+ * We do not care about ->exit_state in fact, but we do -+ * care about ->reap and ->death. If either flag is set, -+ * we must also see ->exit_state != 0. -+ */ -+ if (unlikely(target->exit_state)) { -+ ret = utrace_control_dead(target, utrace, action); -+ if (ret) { -+ spin_unlock(&utrace->lock); -+ return ret; -+ } -+ reset = true; -+ } -+ -+ switch (action) { -+ case UTRACE_STOP: -+ mark_engine_wants_stop(target, engine); -+ if (!reset && !utrace_do_stop(target, utrace)) -+ ret = -EINPROGRESS; -+ reset = false; -+ break; -+ -+ case UTRACE_DETACH: -+ if (engine_wants_stop(engine)) -+ target->utrace_flags &= ~ENGINE_STOP; -+ mark_engine_detached(engine); -+ reset = reset || utrace_do_stop(target, utrace); -+ if (!reset) { -+ /* -+ * As in utrace_set_events(), this barrier ensures -+ * that our engine->flags changes have hit before we -+ * examine utrace->reporting, pairing with the barrier -+ * in start_callback(). If @target has not yet hit -+ * finish_callback() to clear utrace->reporting, we -+ * might be in the middle of a callback to @engine. -+ */ -+ smp_mb(); -+ if (utrace->reporting == engine) -+ ret = -EINPROGRESS; -+ } -+ break; -+ -+ case UTRACE_RESUME: -+ clear_engine_wants_stop(engine); -+ break; -+ -+ case UTRACE_BLOCKSTEP: -+ /* -+ * Resume from stopped, step one block. -+ * We fall through to treat it like UTRACE_SINGLESTEP. -+ */ -+ if (unlikely(!arch_has_block_step())) { -+ WARN(1, "UTRACE_BLOCKSTEP when !arch_has_block_step()"); -+ action = UTRACE_SINGLESTEP; -+ } -+ -+ case UTRACE_SINGLESTEP: -+ /* -+ * Resume from stopped, step one instruction. -+ * We fall through to the UTRACE_REPORT case. -+ */ -+ if (unlikely(!arch_has_single_step())) { -+ WARN(1, -+ "UTRACE_SINGLESTEP when !arch_has_single_step()"); -+ reset = false; -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ -+ case UTRACE_REPORT: -+ /* -+ * Make the thread call tracehook_notify_resume() soon. -+ * But don't bother if it's already been interrupted. -+ * In that case, utrace_get_signal() will be reporting soon. -+ */ -+ clear_engine_wants_stop(engine); -+ if (action < utrace->resume) { -+ utrace->resume = action; -+ set_notify_resume(target); -+ } -+ break; -+ -+ case UTRACE_INTERRUPT: -+ /* -+ * Make the thread call tracehook_get_signal() soon. -+ */ -+ clear_engine_wants_stop(engine); -+ if (utrace->resume == UTRACE_INTERRUPT) -+ break; -+ utrace->resume = UTRACE_INTERRUPT; -+ -+ /* -+ * If it's not already stopped, interrupt it now. We need -+ * the siglock here in case it calls recalc_sigpending() -+ * and clears its own TIF_SIGPENDING. By taking the lock, -+ * we've serialized any later recalc_sigpending() after our -+ * setting of utrace->resume to force it on. -+ */ -+ if (reset) { -+ /* -+ * This is really just to keep the invariant that -+ * TIF_SIGPENDING is set with UTRACE_INTERRUPT. -+ * When it's stopped, we know it's always going -+ * through utrace_get_signal() and will recalculate. -+ */ -+ set_tsk_thread_flag(target, TIF_SIGPENDING); -+ } else { -+ struct sighand_struct *sighand; -+ unsigned long irqflags; -+ sighand = lock_task_sighand(target, &irqflags); -+ if (likely(sighand)) { -+ signal_wake_up(target, 0); -+ unlock_task_sighand(target, &irqflags); -+ } -+ } -+ break; -+ -+ default: -+ BUG(); /* We checked it on entry. */ -+ } -+ -+ /* -+ * Let the thread resume running. If it's not stopped now, -+ * there is nothing more we need to do. -+ */ -+ if (reset) -+ utrace_reset(target, utrace); -+ else -+ spin_unlock(&utrace->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_control); -+ -+/** -+ * utrace_barrier - synchronize with simultaneous tracing callbacks -+ * @target: thread to affect -+ * @engine: engine to affect (can be detached) -+ * -+ * This blocks while @target might be in the midst of making a callback to -+ * @engine. It can be interrupted by signals and will return -%ERESTARTSYS. -+ * A return value of zero means no callback from @target to @engine was -+ * in progress. Any effect of its return value (such as %UTRACE_STOP) has -+ * already been applied to @engine. -+ * -+ * It's not necessary to keep the @target pointer alive for this call. -+ * It's only necessary to hold a ref on @engine. This will return -+ * safely even if @target has been reaped and has no task refs. -+ * -+ * A successful return from utrace_barrier() guarantees its ordering -+ * with respect to utrace_set_events() and utrace_control() calls. If -+ * @target was not properly stopped, event callbacks just disabled might -+ * still be in progress; utrace_barrier() waits until there is no chance -+ * an unwanted callback can be in progress. -+ */ -+int utrace_barrier(struct task_struct *target, struct utrace_engine *engine) -+{ -+ struct utrace *utrace; -+ int ret = -ERESTARTSYS; -+ -+ if (unlikely(target == current)) -+ return 0; -+ -+ do { -+ utrace = get_utrace_lock(target, engine, false); -+ if (unlikely(IS_ERR(utrace))) { -+ ret = PTR_ERR(utrace); -+ if (ret != -ERESTARTSYS) -+ break; -+ } else { -+ /* -+ * All engine state changes are done while -+ * holding the lock, i.e. before we get here. -+ * Since we have the lock, we only need to -+ * worry about @target making a callback. -+ * When it has entered start_callback() but -+ * not yet gotten to finish_callback(), we -+ * will see utrace->reporting == @engine. -+ * When @target doesn't take the lock, it uses -+ * barriers to order setting utrace->reporting -+ * before it examines the engine state. -+ */ -+ if (utrace->reporting != engine) -+ ret = 0; -+ spin_unlock(&utrace->lock); -+ if (!ret) -+ break; -+ } -+ schedule_timeout_interruptible(1); -+ } while (!signal_pending(current)); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_barrier); -+ -+/* -+ * This is local state used for reporting loops, perhaps optimized away. -+ */ -+struct utrace_report { -+ u32 result; -+ enum utrace_resume_action action; -+ enum utrace_resume_action resume_action; -+ bool detaches; -+ bool spurious; -+}; -+ -+#define INIT_REPORT(var) \ -+ struct utrace_report var = { \ -+ .action = UTRACE_RESUME, \ -+ .resume_action = UTRACE_RESUME, \ -+ .spurious = true \ -+ } -+ -+/* -+ * We are now making the report, so clear the flag saying we need one. -+ * When there is a new attach, ->pending_attach is set just so we will -+ * know to do splice_attaching() here before the callback loop. -+ */ -+static enum utrace_resume_action start_report(struct utrace *utrace) -+{ -+ enum utrace_resume_action resume = utrace->resume; -+ if (utrace->pending_attach || -+ (resume > UTRACE_INTERRUPT && resume < UTRACE_RESUME)) { -+ spin_lock(&utrace->lock); -+ splice_attaching(utrace); -+ resume = utrace->resume; -+ if (resume > UTRACE_INTERRUPT) -+ utrace->resume = UTRACE_RESUME; -+ spin_unlock(&utrace->lock); -+ } -+ return resume; -+} -+ -+static inline void finish_report_reset(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report) -+{ -+ if (unlikely(report->spurious || report->detaches)) { -+ spin_lock(&utrace->lock); -+ if (utrace_reset(task, utrace)) -+ report->action = UTRACE_RESUME; -+ } -+} -+ -+/* -+ * Complete a normal reporting pass, pairing with a start_report() call. -+ * This handles any UTRACE_DETACH or UTRACE_REPORT or UTRACE_INTERRUPT -+ * returns from engine callbacks. If @will_not_stop is true and any -+ * engine's last callback used UTRACE_STOP, we do UTRACE_REPORT here to -+ * ensure we stop before user mode. If there were no callbacks made, it -+ * will recompute @task->utrace_flags to avoid another false-positive. -+ */ -+static void finish_report(struct task_struct *task, struct utrace *utrace, -+ struct utrace_report *report, bool will_not_stop) -+{ -+ enum utrace_resume_action resume = report->action; -+ -+ if (resume == UTRACE_STOP) -+ resume = will_not_stop ? UTRACE_REPORT : UTRACE_RESUME; -+ -+ if (resume < utrace->resume) { -+ spin_lock(&utrace->lock); -+ utrace->resume = resume; -+ if (resume == UTRACE_INTERRUPT) -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ else -+ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); -+ spin_unlock(&utrace->lock); -+ } -+ -+ finish_report_reset(task, utrace, report); -+} -+ -+static void finish_callback_report(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report, -+ struct utrace_engine *engine, -+ enum utrace_resume_action action) -+{ -+ if (action == UTRACE_DETACH) { -+ /* -+ * By holding the lock here, we make sure that -+ * utrace_barrier() (really get_utrace_lock()) sees the -+ * effect of this detach. Otherwise utrace_barrier() could -+ * return 0 after this callback had returned UTRACE_DETACH. -+ * This way, a 0 return is an unambiguous indicator that any -+ * callback returning UTRACE_DETACH has indeed caused detach. -+ */ -+ spin_lock(&utrace->lock); -+ engine->ops = &utrace_detached_ops; -+ spin_unlock(&utrace->lock); -+ } -+ -+ /* -+ * If utrace_control() was used, treat that like UTRACE_DETACH here. -+ */ -+ if (engine->ops == &utrace_detached_ops) { -+ report->detaches = true; -+ return; -+ } -+ -+ if (action < report->action) -+ report->action = action; -+ -+ if (action != UTRACE_STOP) { -+ if (action < report->resume_action) -+ report->resume_action = action; -+ -+ if (engine_wants_stop(engine)) { -+ spin_lock(&utrace->lock); -+ clear_engine_wants_stop(engine); -+ spin_unlock(&utrace->lock); -+ } -+ -+ return; -+ } -+ -+ if (!engine_wants_stop(engine)) { -+ spin_lock(&utrace->lock); -+ /* -+ * If utrace_control() came in and detached us -+ * before we got the lock, we must not stop now. -+ */ -+ if (unlikely(engine->ops == &utrace_detached_ops)) -+ report->detaches = true; -+ else -+ mark_engine_wants_stop(task, engine); -+ spin_unlock(&utrace->lock); -+ } -+} -+ -+/* -+ * Apply the return value of one engine callback to @report. -+ * Returns true if @engine detached and should not get any more callbacks. -+ */ -+static bool finish_callback(struct task_struct *task, struct utrace *utrace, -+ struct utrace_report *report, -+ struct utrace_engine *engine, -+ u32 ret) -+{ -+ report->result = ret & ~UTRACE_RESUME_MASK; -+ finish_callback_report(task, utrace, report, engine, -+ utrace_resume_action(ret)); -+ -+ /* -+ * Now that we have applied the effect of the return value, -+ * clear this so that utrace_barrier() can stop waiting. -+ * A subsequent utrace_control() can stop or resume @engine -+ * and know this was ordered after its callback's action. -+ * -+ * We don't need any barriers here because utrace_barrier() -+ * takes utrace->lock. If we touched engine->flags above, -+ * the lock guaranteed this change was before utrace_barrier() -+ * examined utrace->reporting. -+ */ -+ utrace->reporting = NULL; -+ -+ /* -+ * We've just done an engine callback. These are allowed to sleep, -+ * though all well-behaved ones restrict that to blocking kalloc() -+ * or quickly-acquired mutex_lock() and the like. This is a good -+ * place to make sure tracing engines don't introduce too much -+ * latency under voluntary preemption. -+ */ -+ might_sleep(); -+ -+ return engine->ops == &utrace_detached_ops; -+} -+ -+/* -+ * Start the callbacks for @engine to consider @event (a bit mask). -+ * This makes the report_quiesce() callback first. If @engine wants -+ * a specific callback for @event, we return the ops vector to use. -+ * If not, we return NULL. The return value from the ops->callback -+ * function called should be passed to finish_callback(). -+ */ -+static const struct utrace_engine_ops *start_callback( -+ struct utrace *utrace, struct utrace_report *report, -+ struct utrace_engine *engine, struct task_struct *task, -+ unsigned long event) -+{ -+ const struct utrace_engine_ops *ops; -+ unsigned long want; -+ -+ /* -+ * This barrier ensures that we've set utrace->reporting before -+ * we examine engine->flags or engine->ops. utrace_barrier() -+ * relies on this ordering to indicate that the effect of any -+ * utrace_control() and utrace_set_events() calls is in place -+ * by the time utrace->reporting can be seen to be NULL. -+ */ -+ utrace->reporting = engine; -+ smp_mb(); -+ -+ /* -+ * This pairs with the barrier in mark_engine_detached(). -+ * It makes sure that we never see the old ops vector with -+ * the new flags, in case the original vector had no report_quiesce. -+ */ -+ want = engine->flags; -+ smp_rmb(); -+ ops = engine->ops; -+ -+ if ((want & UTRACE_EVENT(QUIESCE)) || ops == &utrace_detached_ops) { -+ if (finish_callback(task, utrace, report, engine, -+ (*ops->report_quiesce)(report->action, -+ engine, event))) -+ return NULL; -+ -+ if (!event) { -+ /* We only got here to report QUIESCE */ -+ report->spurious = false; -+ return NULL; -+ } -+ -+ /* -+ * finish_callback() reset utrace->reporting after the -+ * quiesce callback. Now we set it again (as above) -+ * before re-examining engine->flags, which could have -+ * been changed synchronously by ->report_quiesce or -+ * asynchronously by utrace_control() or utrace_set_events(). -+ */ -+ utrace->reporting = engine; -+ smp_mb(); -+ want = engine->flags; -+ } -+ -+ if (want & ENGINE_STOP) -+ report->action = UTRACE_STOP; -+ -+ if (want & event) { -+ report->spurious = false; -+ return ops; -+ } -+ -+ utrace->reporting = NULL; -+ return NULL; -+} -+ -+/* -+ * Do a normal reporting pass for engines interested in @event. -+ * @callback is the name of the member in the ops vector, and remaining -+ * args are the extras it takes after the standard three args. -+ */ -+#define REPORT_CALLBACKS(rev, task, utrace, report, event, callback, ...) \ -+ do { \ -+ struct utrace_engine *engine; \ -+ const struct utrace_engine_ops *ops; \ -+ list_for_each_entry##rev(engine, &utrace->attached, entry) { \ -+ ops = start_callback(utrace, report, engine, task, \ -+ event); \ -+ if (!ops) \ -+ continue; \ -+ finish_callback(task, utrace, report, engine, \ -+ (*ops->callback)(__VA_ARGS__)); \ -+ } \ -+ } while (0) -+#define REPORT(task, utrace, report, event, callback, ...) \ -+ do { \ -+ start_report(utrace); \ -+ REPORT_CALLBACKS(, task, utrace, report, event, callback, \ -+ (report)->action, engine, ## __VA_ARGS__); \ -+ finish_report(task, utrace, report, true); \ -+ } while (0) -+ -+/* -+ * Called iff UTRACE_EVENT(EXEC) flag is set. -+ */ -+void utrace_report_exec(struct linux_binfmt *fmt, struct linux_binprm *bprm, -+ struct pt_regs *regs) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(EXEC), -+ report_exec, fmt, bprm, regs); -+} -+ -+static u32 do_report_syscall_entry(struct pt_regs *regs, -+ struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report, -+ u32 resume_report) -+{ -+ start_report(utrace); -+ REPORT_CALLBACKS(_reverse, task, utrace, report, -+ UTRACE_EVENT(SYSCALL_ENTRY), report_syscall_entry, -+ resume_report | report->result | report->action, -+ engine, regs); -+ finish_report(task, utrace, report, false); -+ -+ if (report->action != UTRACE_STOP) -+ return 0; -+ -+ utrace_stop(task, utrace, report->resume_action); -+ -+ if (fatal_signal_pending(task)) { -+ /* -+ * We are continuing despite UTRACE_STOP because of a -+ * SIGKILL. Don't let the system call actually proceed. -+ */ -+ report->result = UTRACE_SYSCALL_ABORT; -+ } else if (utrace->resume <= UTRACE_REPORT) { -+ /* -+ * If we've been asked for another report after our stop, -+ * go back to report (and maybe stop) again before we run -+ * the system call. The second (and later) reports are -+ * marked with the UTRACE_SYSCALL_RESUMED flag so that -+ * engines know this is a second report at the same -+ * entry. This gives them the chance to examine the -+ * registers anew after they might have been changed -+ * while we were stopped. -+ */ -+ report->detaches = false; -+ report->spurious = true; -+ report->action = report->resume_action = UTRACE_RESUME; -+ return UTRACE_SYSCALL_RESUMED; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Called iff UTRACE_EVENT(SYSCALL_ENTRY) flag is set. -+ * Return true to prevent the system call. -+ */ -+bool utrace_report_syscall_entry(struct pt_regs *regs) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ u32 resume_report = 0; -+ -+ do { -+ resume_report = do_report_syscall_entry(regs, task, utrace, -+ &report, resume_report); -+ } while (resume_report); -+ -+ return utrace_syscall_action(report.result) == UTRACE_SYSCALL_ABORT; -+} -+ -+/* -+ * Called iff UTRACE_EVENT(SYSCALL_EXIT) flag is set. -+ */ -+void utrace_report_syscall_exit(struct pt_regs *regs) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(SYSCALL_EXIT), -+ report_syscall_exit, regs); -+} -+ -+/* -+ * Called iff UTRACE_EVENT(CLONE) flag is set. -+ * This notification call blocks the wake_up_new_task call on the child. -+ * So we must not quiesce here. tracehook_report_clone_complete will do -+ * a quiescence check momentarily. -+ */ -+void utrace_report_clone(unsigned long clone_flags, struct task_struct *child) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ /* -+ * We don't use the REPORT() macro here, because we need -+ * to clear utrace->cloning before finish_report(). -+ * After finish_report(), utrace can be a stale pointer -+ * in cases when report.action is still UTRACE_RESUME. -+ */ -+ start_report(utrace); -+ utrace->cloning = child; -+ -+ REPORT_CALLBACKS(, task, utrace, &report, -+ UTRACE_EVENT(CLONE), report_clone, -+ report.action, engine, clone_flags, child); -+ -+ utrace->cloning = NULL; -+ finish_report(task, utrace, &report, !(clone_flags & CLONE_VFORK)); -+ -+ /* -+ * For a vfork, we will go into an uninterruptible block waiting -+ * for the child. We need UTRACE_STOP to happen before this, not -+ * after. For CLONE_VFORK, utrace_finish_vfork() will be called. -+ */ -+ if (report.action == UTRACE_STOP && (clone_flags & CLONE_VFORK)) { -+ spin_lock(&utrace->lock); -+ utrace->vfork_stop = 1; -+ spin_unlock(&utrace->lock); -+ } -+} -+ -+/* -+ * We're called after utrace_report_clone() for a CLONE_VFORK. -+ * If UTRACE_STOP was left from the clone report, we stop here. -+ * After this, we'll enter the uninterruptible wait_for_completion() -+ * waiting for the child. -+ */ -+void utrace_finish_vfork(struct task_struct *task) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ if (utrace->vfork_stop) { -+ spin_lock(&utrace->lock); -+ utrace->vfork_stop = 0; -+ spin_unlock(&utrace->lock); -+ utrace_stop(task, utrace, UTRACE_RESUME); /* XXX */ -+ } -+} -+ -+/* -+ * Called iff UTRACE_EVENT(JCTL) flag is set. -+ * -+ * Called with siglock held. -+ */ -+void utrace_report_jctl(int notify, int what) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ -+ spin_unlock_irq(&task->sighand->siglock); -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(JCTL), -+ report_jctl, what, notify); -+ -+ spin_lock_irq(&task->sighand->siglock); -+} -+ -+/* -+ * Called iff UTRACE_EVENT(EXIT) flag is set. -+ */ -+void utrace_report_exit(long *exit_code) -+{ -+ struct task_struct *task = current; -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ long orig_code = *exit_code; -+ -+ REPORT(task, utrace, &report, UTRACE_EVENT(EXIT), -+ report_exit, orig_code, exit_code); -+ -+ if (report.action == UTRACE_STOP) -+ utrace_stop(task, utrace, report.resume_action); -+} -+ -+/* -+ * Called iff UTRACE_EVENT(DEATH) or UTRACE_EVENT(QUIESCE) flag is set. -+ * -+ * It is always possible that we are racing with utrace_release_task here. -+ * For this reason, utrace_release_task checks for the event bits that get -+ * us here, and delays its cleanup for us to do. -+ */ -+void utrace_report_death(struct task_struct *task, bool group_dead, int signal) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ INIT_REPORT(report); -+ -+ BUG_ON(!task->exit_state); -+ -+ /* -+ * We are presently considered "quiescent"--which is accurate -+ * inasmuch as we won't run any more user instructions ever again. -+ * But for utrace_control and utrace_set_events to be robust, they -+ * must be sure whether or not we will run any more callbacks. If -+ * a call comes in before we do, taking the lock here synchronizes -+ * us so we don't run any callbacks just disabled. Calls that come -+ * in while we're running the callbacks will see the exit.death -+ * flag and know that we are not yet fully quiescent for purposes -+ * of detach bookkeeping. -+ */ -+ spin_lock(&utrace->lock); -+ BUG_ON(utrace->death); -+ utrace->death = 1; -+ utrace->resume = UTRACE_RESUME; -+ splice_attaching(utrace); -+ spin_unlock(&utrace->lock); -+ -+ REPORT_CALLBACKS(, task, utrace, &report, UTRACE_EVENT(DEATH), -+ report_death, engine, group_dead, signal); -+ -+ utrace_maybe_reap(task, utrace, false); -+} -+ -+/* -+ * Finish the last reporting pass before returning to user mode. -+ */ -+static void finish_resume_report(struct task_struct *task, -+ struct utrace *utrace, -+ struct utrace_report *report) -+{ -+ finish_report_reset(task, utrace, report); -+ -+ switch (report->action) { -+ case UTRACE_STOP: -+ utrace_stop(task, utrace, report->resume_action); -+ break; -+ -+ case UTRACE_INTERRUPT: -+ if (!signal_pending(task)) -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ break; -+ -+ case UTRACE_BLOCKSTEP: -+ if (likely(arch_has_block_step())) { -+ if (!ptrace_wants_step(task)) -+ user_enable_block_step(task); -+ break; -+ } -+ -+ /* -+ * This means some callback is to blame for failing -+ * to check arch_has_block_step() itself. Warn and -+ * then fall through to treat it as SINGLESTEP. -+ */ -+ WARN(1, "UTRACE_BLOCKSTEP when !arch_has_block_step()"); -+ -+ case UTRACE_SINGLESTEP: -+ if (likely(arch_has_single_step())) { -+ if (!ptrace_wants_step(task)) -+ user_enable_single_step(task); -+ } else { -+ /* -+ * This means some callback is to blame for failing -+ * to check arch_has_single_step() itself. Spew -+ * about it so the loser will fix his module. -+ */ -+ WARN(1, -+ "UTRACE_SINGLESTEP when !arch_has_single_step()"); -+ } -+ break; -+ -+ case UTRACE_REPORT: -+ case UTRACE_RESUME: -+ default: -+ if (!ptrace_wants_step(task)) -+ user_disable_single_step(task); -+ break; -+ } -+} -+ -+/* -+ * This is called when TIF_NOTIFY_RESUME had been set (and is now clear). -+ * We are close to user mode, and this is the place to report or stop. -+ * When we return, we're going to user mode or into the signals code. -+ */ -+void utrace_resume(struct task_struct *task, struct pt_regs *regs) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ INIT_REPORT(report); -+ struct utrace_engine *engine; -+ -+ /* -+ * Some machines get here with interrupts disabled. The same arch -+ * code path leads to calling into get_signal_to_deliver(), which -+ * implicitly reenables them by virtue of spin_unlock_irq. -+ */ -+ if (irqs_disabled()) /* make trace_hardirqs_on() happy */ -+ local_irq_enable(); -+ -+ /* -+ * If this flag is still set it's because there was a signal -+ * handler setup done but no report_signal following it. Clear -+ * the flag before we get to user so it doesn't confuse us later. -+ */ -+ if (unlikely(utrace->signal_handler)) { -+ spin_lock(&utrace->lock); -+ utrace->signal_handler = 0; -+ spin_unlock(&utrace->lock); -+ } -+ -+ /* -+ * Update our bookkeeping even if there are no callbacks made here. -+ */ -+ report.action = start_report(utrace); -+ -+ switch (report.action) { -+ case UTRACE_RESUME: -+ /* -+ * Anything we might have done was already handled by -+ * utrace_get_signal(), or this is an entirely spurious -+ * call. (The arch might use TIF_NOTIFY_RESUME for other -+ * purposes as well as calling us.) -+ */ -+ return; -+ case UTRACE_REPORT: -+ if (unlikely(!(task->utrace_flags & UTRACE_EVENT(QUIESCE)))) -+ break; -+ /* -+ * Do a simple reporting pass, with no specific -+ * callback after report_quiesce. -+ */ -+ report.action = UTRACE_RESUME; -+ list_for_each_entry(engine, &utrace->attached, entry) -+ start_callback(utrace, &report, engine, task, 0); -+ break; -+ default: -+ /* -+ * Even if this report was truly spurious, there is no need -+ * for utrace_reset() now. TIF_NOTIFY_RESUME was already -+ * cleared--it doesn't stay spuriously set. -+ */ -+ report.spurious = false; -+ break; -+ } -+ -+ /* -+ * Finish the report and either stop or get ready to resume. -+ * If utrace->resume was not UTRACE_REPORT, this applies its -+ * effect now (i.e. step or interrupt). -+ */ -+ finish_resume_report(task, utrace, &report); -+} -+ -+/* -+ * Return true if current has forced signal_pending(). -+ * -+ * This is called only when current->utrace_flags is nonzero, so we know -+ * that current->utrace must be set. It's not inlined in tracehook.h -+ * just so that struct utrace can stay opaque outside this file. -+ */ -+bool utrace_interrupt_pending(void) -+{ -+ return task_utrace_struct(current)->resume == UTRACE_INTERRUPT; -+} -+ -+/* -+ * Take the siglock and push @info back on our queue. -+ * Returns with @task->sighand->siglock held. -+ */ -+static void push_back_signal(struct task_struct *task, siginfo_t *info) -+ __acquires(task->sighand->siglock) -+{ -+ struct sigqueue *q; -+ -+ if (unlikely(!info->si_signo)) { /* Oh, a wise guy! */ -+ spin_lock_irq(&task->sighand->siglock); -+ return; -+ } -+ -+ q = sigqueue_alloc(); -+ if (likely(q)) { -+ q->flags = 0; -+ copy_siginfo(&q->info, info); -+ } -+ -+ spin_lock_irq(&task->sighand->siglock); -+ -+ sigaddset(&task->pending.signal, info->si_signo); -+ if (likely(q)) -+ list_add(&q->list, &task->pending.list); -+ -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+} -+ -+/* -+ * This is the hook from the signals code, called with the siglock held. -+ * Here is the ideal place to stop. We also dequeue and intercept signals. -+ */ -+int utrace_get_signal(struct task_struct *task, struct pt_regs *regs, -+ siginfo_t *info, struct k_sigaction *return_ka) -+ __releases(task->sighand->siglock) -+ __acquires(task->sighand->siglock) -+{ -+ struct utrace *utrace; -+ struct k_sigaction *ka; -+ INIT_REPORT(report); -+ struct utrace_engine *engine; -+ const struct utrace_engine_ops *ops; -+ unsigned long event, want; -+ u32 ret; -+ int signr; -+ -+ utrace = task_utrace_struct(task); -+ if (utrace->resume < UTRACE_RESUME || -+ utrace->pending_attach || utrace->signal_handler) { -+ enum utrace_resume_action resume; -+ -+ /* -+ * We've been asked for an explicit report before we -+ * even check for pending signals. -+ */ -+ -+ spin_unlock_irq(&task->sighand->siglock); -+ -+ spin_lock(&utrace->lock); -+ -+ splice_attaching(utrace); -+ -+ report.result = utrace->signal_handler ? -+ UTRACE_SIGNAL_HANDLER : UTRACE_SIGNAL_REPORT; -+ utrace->signal_handler = 0; -+ -+ resume = utrace->resume; -+ utrace->resume = UTRACE_RESUME; -+ -+ spin_unlock(&utrace->lock); -+ -+ /* -+ * Make sure signal_pending() only returns true -+ * if there are real signals pending. -+ */ -+ if (signal_pending(task)) { -+ spin_lock_irq(&task->sighand->siglock); -+ recalc_sigpending(); -+ spin_unlock_irq(&task->sighand->siglock); -+ } -+ -+ if (resume > UTRACE_REPORT) { -+ /* -+ * We only got here to process utrace->resume. -+ * Despite no callbacks, this report is not spurious. -+ */ -+ report.action = resume; -+ report.spurious = false; -+ finish_resume_report(task, utrace, &report); -+ return -1; -+ } else if (!(task->utrace_flags & UTRACE_EVENT(QUIESCE))) { -+ /* -+ * We only got here to clear utrace->signal_handler. -+ */ -+ return -1; -+ } -+ -+ /* -+ * Do a reporting pass for no signal, just for EVENT(QUIESCE). -+ * The engine callbacks can fill in *info and *return_ka. -+ * We'll pass NULL for the @orig_ka argument to indicate -+ * that there was no original signal. -+ */ -+ event = 0; -+ ka = NULL; -+ memset(return_ka, 0, sizeof *return_ka); -+ } else if (!(task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) || -+ unlikely(task->jobctl & JOBCTL_PENDING_MASK)) { -+ /* -+ * If no engine is interested in intercepting signals or -+ * we must stop, let the caller just dequeue them normally -+ * or participate in group-stop. -+ */ -+ return 0; -+ } else { -+ /* -+ * Steal the next signal so we can let tracing engines -+ * examine it. From the signal number and sigaction, -+ * determine what normal delivery would do. If no -+ * engine perturbs it, we'll do that by returning the -+ * signal number after setting *return_ka. -+ */ -+ signr = dequeue_signal(task, &task->blocked, info); -+ if (signr == 0) -+ return signr; -+ BUG_ON(signr != info->si_signo); -+ -+ ka = &task->sighand->action[signr - 1]; -+ *return_ka = *ka; -+ -+ /* -+ * We are never allowed to interfere with SIGKILL. -+ * Just punt after filling in *return_ka for our caller. -+ */ -+ if (signr == SIGKILL) -+ return signr; -+ -+ if (ka->sa.sa_handler == SIG_IGN) { -+ event = UTRACE_EVENT(SIGNAL_IGN); -+ report.result = UTRACE_SIGNAL_IGN; -+ } else if (ka->sa.sa_handler != SIG_DFL) { -+ event = UTRACE_EVENT(SIGNAL); -+ report.result = UTRACE_SIGNAL_DELIVER; -+ } else if (sig_kernel_coredump(signr)) { -+ event = UTRACE_EVENT(SIGNAL_CORE); -+ report.result = UTRACE_SIGNAL_CORE; -+ } else if (sig_kernel_ignore(signr)) { -+ event = UTRACE_EVENT(SIGNAL_IGN); -+ report.result = UTRACE_SIGNAL_IGN; -+ } else if (signr == SIGSTOP) { -+ event = UTRACE_EVENT(SIGNAL_STOP); -+ report.result = UTRACE_SIGNAL_STOP; -+ } else if (sig_kernel_stop(signr)) { -+ event = UTRACE_EVENT(SIGNAL_STOP); -+ report.result = UTRACE_SIGNAL_TSTP; -+ } else { -+ event = UTRACE_EVENT(SIGNAL_TERM); -+ report.result = UTRACE_SIGNAL_TERM; -+ } -+ -+ /* -+ * Now that we know what event type this signal is, we -+ * can short-circuit if no engines care about those. -+ */ -+ if ((task->utrace_flags & (event | UTRACE_EVENT(QUIESCE))) == 0) -+ return signr; -+ -+ /* -+ * We have some interested engines, so tell them about -+ * the signal and let them change its disposition. -+ */ -+ spin_unlock_irq(&task->sighand->siglock); -+ } -+ -+ /* -+ * This reporting pass chooses what signal disposition we'll act on. -+ */ -+ list_for_each_entry(engine, &utrace->attached, entry) { -+ /* -+ * See start_callback() comment about this barrier. -+ */ -+ utrace->reporting = engine; -+ smp_mb(); -+ -+ /* -+ * This pairs with the barrier in mark_engine_detached(), -+ * see start_callback() comments. -+ */ -+ want = engine->flags; -+ smp_rmb(); -+ ops = engine->ops; -+ -+ if ((want & (event | UTRACE_EVENT(QUIESCE))) == 0) { -+ utrace->reporting = NULL; -+ continue; -+ } -+ -+ if (ops->report_signal) -+ ret = (*ops->report_signal)( -+ report.result | report.action, engine, -+ regs, info, ka, return_ka); -+ else -+ ret = (report.result | (*ops->report_quiesce)( -+ report.action, engine, event)); -+ -+ /* -+ * Avoid a tight loop reporting again and again if some -+ * engine is too stupid. -+ */ -+ switch (utrace_resume_action(ret)) { -+ default: -+ break; -+ case UTRACE_INTERRUPT: -+ case UTRACE_REPORT: -+ ret = (ret & ~UTRACE_RESUME_MASK) | UTRACE_RESUME; -+ break; -+ } -+ -+ finish_callback(task, utrace, &report, engine, ret); -+ } -+ -+ /* -+ * We express the chosen action to the signals code in terms -+ * of a representative signal whose default action does it. -+ * Our caller uses our return value (signr) to decide what to -+ * do, but uses info->si_signo as the signal number to report. -+ */ -+ switch (utrace_signal_action(report.result)) { -+ case UTRACE_SIGNAL_TERM: -+ signr = SIGTERM; -+ break; -+ -+ case UTRACE_SIGNAL_CORE: -+ signr = SIGQUIT; -+ break; -+ -+ case UTRACE_SIGNAL_STOP: -+ signr = SIGSTOP; -+ break; -+ -+ case UTRACE_SIGNAL_TSTP: -+ signr = SIGTSTP; -+ break; -+ -+ case UTRACE_SIGNAL_DELIVER: -+ signr = info->si_signo; -+ -+ if (return_ka->sa.sa_handler == SIG_DFL) { -+ /* -+ * We'll do signr's normal default action. -+ * For ignore, we'll fall through below. -+ * For stop/death, break locks and returns it. -+ */ -+ if (likely(signr) && !sig_kernel_ignore(signr)) -+ break; -+ } else if (return_ka->sa.sa_handler != SIG_IGN && -+ likely(signr)) { -+ /* -+ * Complete the bookkeeping after the report. -+ * The handler will run. If an engine wanted to -+ * stop or step, then make sure we do another -+ * report after signal handler setup. -+ */ -+ if (report.action != UTRACE_RESUME) -+ report.action = UTRACE_INTERRUPT; -+ finish_report(task, utrace, &report, true); -+ -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) -+ push_back_signal(task, info); -+ else -+ spin_lock_irq(&task->sighand->siglock); -+ -+ /* -+ * We do the SA_ONESHOT work here since the -+ * normal path will only touch *return_ka now. -+ */ -+ if (unlikely(return_ka->sa.sa_flags & SA_ONESHOT)) { -+ return_ka->sa.sa_flags &= ~SA_ONESHOT; -+ if (likely(valid_signal(signr))) { -+ ka = &task->sighand->action[signr - 1]; -+ ka->sa.sa_handler = SIG_DFL; -+ } -+ } -+ -+ return signr; -+ } -+ -+ /* Fall through for an ignored signal. */ -+ -+ case UTRACE_SIGNAL_IGN: -+ case UTRACE_SIGNAL_REPORT: -+ default: -+ /* -+ * If the signal is being ignored, then we are on the way -+ * directly back to user mode. We can stop here, or step, -+ * as in utrace_resume(), above. After we've dealt with that, -+ * our caller will relock and come back through here. -+ */ -+ finish_resume_report(task, utrace, &report); -+ -+ if (unlikely(fatal_signal_pending(task))) { -+ /* -+ * The only reason we woke up now was because of a -+ * SIGKILL. Don't do normal dequeuing in case it -+ * might get a signal other than SIGKILL. That would -+ * perturb the death state so it might differ from -+ * what the debugger would have allowed to happen. -+ * Instead, pluck out just the SIGKILL to be sure -+ * we'll die immediately with nothing else different -+ * from the quiescent state the debugger wanted us in. -+ */ -+ sigset_t sigkill_only; -+ siginitsetinv(&sigkill_only, sigmask(SIGKILL)); -+ spin_lock_irq(&task->sighand->siglock); -+ signr = dequeue_signal(task, &sigkill_only, info); -+ BUG_ON(signr != SIGKILL); -+ *return_ka = task->sighand->action[SIGKILL - 1]; -+ return signr; -+ } -+ -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) { -+ push_back_signal(task, info); -+ spin_unlock_irq(&task->sighand->siglock); -+ } -+ -+ return -1; -+ } -+ -+ /* -+ * Complete the bookkeeping after the report. -+ * This sets utrace->resume if UTRACE_STOP was used. -+ */ -+ finish_report(task, utrace, &report, true); -+ -+ return_ka->sa.sa_handler = SIG_DFL; -+ -+ /* -+ * If this signal is fatal, si_signo gets through as exit_code. -+ * We can't allow a completely bogus value there or else core -+ * kernel code can freak out. (If an engine wants to control -+ * the exit_code value exactly, it can do so in report_exit.) -+ * We'll produce a big complaint in dmesg, but won't crash. -+ * That's nicer for debugging your utrace engine. -+ */ -+ if (unlikely(info->si_signo & 0x80)) { -+ WARN(1, "utrace engine left bogus si_signo value!"); -+ info->si_signo = SIGTRAP; -+ } -+ -+ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) -+ push_back_signal(task, info); -+ else -+ spin_lock_irq(&task->sighand->siglock); -+ -+ if (sig_kernel_stop(signr)) -+ task->jobctl |= JOBCTL_STOP_DEQUEUED; -+ -+ return signr; -+} -+ -+/* -+ * This gets called after a signal handler has been set up. -+ * We set a flag so the next report knows it happened. -+ * If we're already stepping, make sure we do a report_signal. -+ * If not, make sure we get into utrace_resume() where we can -+ * clear the signal_handler flag before resuming. -+ */ -+void utrace_signal_handler(struct task_struct *task, int stepping) -+{ -+ struct utrace *utrace = task_utrace_struct(task); -+ -+ spin_lock(&utrace->lock); -+ -+ utrace->signal_handler = 1; -+ if (utrace->resume > UTRACE_INTERRUPT) { -+ if (stepping) { -+ utrace->resume = UTRACE_INTERRUPT; -+ set_tsk_thread_flag(task, TIF_SIGPENDING); -+ } else if (utrace->resume == UTRACE_RESUME) { -+ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); -+ } -+ } -+ -+ spin_unlock(&utrace->lock); -+} -+ -+/** -+ * utrace_prepare_examine - prepare to examine thread state -+ * @target: thread of interest, a &struct task_struct pointer -+ * @engine: engine pointer returned by utrace_attach_task() -+ * @exam: temporary state, a &struct utrace_examiner pointer -+ * -+ * This call prepares to safely examine the thread @target using -+ * &struct user_regset calls, or direct access to thread-synchronous fields. -+ * -+ * When @target is current, this call is superfluous. When @target is -+ * another thread, it must be held stopped via %UTRACE_STOP by @engine. -+ * -+ * This call may block the caller until @target stays stopped, so it must -+ * be called only after the caller is sure @target is about to unschedule. -+ * This means a zero return from a utrace_control() call on @engine giving -+ * %UTRACE_STOP, or a report_quiesce() or report_signal() callback to -+ * @engine that used %UTRACE_STOP in its return value. -+ * -+ * Returns -%ESRCH if @target is dead or -%EINVAL if %UTRACE_STOP was -+ * not used. If @target has started running again despite %UTRACE_STOP -+ * (for %SIGKILL or a spurious wakeup), this call returns -%EAGAIN. -+ * -+ * When this call returns zero, it's safe to use &struct user_regset -+ * calls and task_user_regset_view() on @target and to examine some of -+ * its fields directly. When the examination is complete, a -+ * utrace_finish_examine() call must follow to check whether it was -+ * completed safely. -+ */ -+int utrace_prepare_examine(struct task_struct *target, -+ struct utrace_engine *engine, -+ struct utrace_examiner *exam) -+{ -+ int ret = 0; -+ -+ if (unlikely(target == current)) -+ return 0; -+ -+ rcu_read_lock(); -+ if (unlikely(!engine_wants_stop(engine))) -+ ret = -EINVAL; -+ else if (unlikely(target->exit_state)) -+ ret = -ESRCH; -+ else { -+ exam->state = target->state; -+ if (unlikely(exam->state == TASK_RUNNING)) -+ ret = -EAGAIN; -+ else -+ get_task_struct(target); -+ } -+ rcu_read_unlock(); -+ -+ if (likely(!ret)) { -+ exam->ncsw = wait_task_inactive(target, exam->state); -+ put_task_struct(target); -+ if (unlikely(!exam->ncsw)) -+ ret = -EAGAIN; -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_prepare_examine); -+ -+/** -+ * utrace_finish_examine - complete an examination of thread state -+ * @target: thread of interest, a &struct task_struct pointer -+ * @engine: engine pointer returned by utrace_attach_task() -+ * @exam: pointer passed to utrace_prepare_examine() call -+ * -+ * This call completes an examination on the thread @target begun by a -+ * paired utrace_prepare_examine() call with the same arguments that -+ * returned success (zero). -+ * -+ * When @target is current, this call is superfluous. When @target is -+ * another thread, this returns zero if @target has remained unscheduled -+ * since the paired utrace_prepare_examine() call returned zero. -+ * -+ * When this returns an error, any examination done since the paired -+ * utrace_prepare_examine() call is unreliable and the data extracted -+ * should be discarded. The error is -%EINVAL if @engine is not -+ * keeping @target stopped, or -%EAGAIN if @target woke up unexpectedly. -+ */ -+int utrace_finish_examine(struct task_struct *target, -+ struct utrace_engine *engine, -+ struct utrace_examiner *exam) -+{ -+ int ret = 0; -+ -+ if (unlikely(target == current)) -+ return 0; -+ -+ rcu_read_lock(); -+ if (unlikely(!engine_wants_stop(engine))) -+ ret = -EINVAL; -+ else if (unlikely(target->state != exam->state)) -+ ret = -EAGAIN; -+ else -+ get_task_struct(target); -+ rcu_read_unlock(); -+ -+ if (likely(!ret)) { -+ unsigned long ncsw = wait_task_inactive(target, exam->state); -+ if (unlikely(ncsw != exam->ncsw)) -+ ret = -EAGAIN; -+ put_task_struct(target); -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(utrace_finish_examine); -+ -+/* -+ * This is declared in linux/regset.h and defined in machine-dependent -+ * code. We put the export here to ensure no machine forgets it. -+ */ -+EXPORT_SYMBOL_GPL(task_user_regset_view); -+ -+/* -+ * Called with rcu_read_lock() held. -+ */ -+void task_utrace_proc_status(struct seq_file *m, struct task_struct *p) -+{ -+ seq_printf(m, "Utrace:\t%lx\n", p->utrace_flags); -+} --- -1.7.9.1 - diff --git a/x86-add-io_apic_ops-to-allow-interception.patch b/x86-add-io_apic_ops-to-allow-interception.patch deleted file mode 100644 index c82d21fff..000000000 --- a/x86-add-io_apic_ops-to-allow-interception.patch +++ /dev/null @@ -1,135 +0,0 @@ -From: Jeremy Fitzhardinge - -Xen dom0 needs to paravirtualize IO operations to the IO APIC, so add -a io_apic_ops for it to intercept. Do this as ops structure because -there's at least some chance that another paravirtualized environment -may want to intercept these. - -[ Impact: indirect IO APIC access via io_apic_ops ] - -Signed-off-by: Jeremy Fitzhardinge -Signed-off-by: Konrad Rzeszutek Wilk -Acked-by: Suresh Siddha ---- - arch/x86/include/asm/io_apic.h | 9 +++++++ - arch/x86/kernel/apic/io_apic.c | 50 +++++++++++++++++++++++++++++++++++++-- - 2 files changed, 56 insertions(+), 3 deletions(-) - -diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h -index 690d1cc..190d8c2 100644 ---- a/arch/x86/include/asm/io_apic.h -+++ b/arch/x86/include/asm/io_apic.h -@@ -21,6 +21,15 @@ - #define IO_APIC_REDIR_LEVEL_TRIGGER (1 << 15) - #define IO_APIC_REDIR_MASKED (1 << 16) - -+struct io_apic_ops { -+ void (*init)(void); -+ unsigned int (*read)(unsigned int apic, unsigned int reg); -+ void (*write)(unsigned int apic, unsigned int reg, unsigned int value); -+ void (*modify)(unsigned int apic, unsigned int reg, unsigned int value); -+}; -+ -+void __init set_io_apic_ops(const struct io_apic_ops *); -+ - /* - * The structure of the IO-APIC: - */ -diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c -index fb07275..bf120234 100644 ---- a/arch/x86/kernel/apic/io_apic.c -+++ b/arch/x86/kernel/apic/io_apic.c -@@ -67,6 +67,25 @@ - #define for_each_irq_pin(entry, head) \ - for (entry = head; entry; entry = entry->next) - -+static void __init __ioapic_init_mappings(void); -+static unsigned int __io_apic_read(unsigned int apic, unsigned int reg); -+static void __io_apic_write(unsigned int apic, unsigned int reg, -+ unsigned int val); -+static void __io_apic_modify(unsigned int apic, unsigned int reg, -+ unsigned int val); -+ -+static struct io_apic_ops io_apic_ops = { -+ .init = __ioapic_init_mappings, -+ .read = __io_apic_read, -+ .write = __io_apic_write, -+ .modify = __io_apic_modify, -+}; -+ -+void __init set_io_apic_ops(const struct io_apic_ops *ops) -+{ -+ io_apic_ops = *ops; -+} -+ - /* - * Is the SiS APIC rmw bug present ? - * -1 = don't know, 0 = no, 1 = yes -@@ -294,6 +313,24 @@ static void free_irq_at(unsigned int at, struct irq_cfg *cfg) - irq_free_desc(at); - } - -+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) -+{ -+ return io_apic_ops.read(apic, reg); -+} -+ -+static inline void io_apic_write(unsigned int apic, unsigned int reg, -+ unsigned int value) -+{ -+ io_apic_ops.write(apic, reg, value); -+} -+ -+static inline void io_apic_modify(unsigned int apic, unsigned int reg, -+ unsigned int value) -+{ -+ io_apic_ops.modify(apic, reg, value); -+} -+ -+ - struct io_apic { - unsigned int index; - unsigned int unused[3]; -@@ -314,14 +351,15 @@ static inline void io_apic_eoi(unsigned int apic, unsigned int vector) - writel(vector, &io_apic->eoi); - } - --static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) -+static unsigned int __io_apic_read(unsigned int apic, unsigned int reg) - { - struct io_apic __iomem *io_apic = io_apic_base(apic); - writel(reg, &io_apic->index); - return readl(&io_apic->data); - } - --static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) -+static void __io_apic_write(unsigned int apic, unsigned int reg, -+ unsigned int value) - { - struct io_apic __iomem *io_apic = io_apic_base(apic); - writel(reg, &io_apic->index); -@@ -334,7 +372,8 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i - * - * Older SiS APIC requires we rewrite the index register - */ --static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) -+static void __io_apic_modify(unsigned int apic, unsigned int reg, -+ unsigned int value) - { - struct io_apic __iomem *io_apic = io_apic_base(apic); - -@@ -3873,6 +3912,11 @@ static struct resource * __init ioapic_setup_resources(int nr_ioapics) - - void __init ioapic_and_gsi_init(void) - { -+ io_apic_ops.init(); -+} -+ -+static void __init __ioapic_init_mappings(void) -+{ - unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; - struct resource *ioapic_res; - int i; --- -1.7.7.5 - diff --git a/x86-apic_ops-Replace-apic_ops-with-x86_apic_ops.patch b/x86-apic_ops-Replace-apic_ops-with-x86_apic_ops.patch deleted file mode 100644 index ddbb92412..000000000 --- a/x86-apic_ops-Replace-apic_ops-with-x86_apic_ops.patch +++ /dev/null @@ -1,258 +0,0 @@ -. which makes the code fit within the rest of the x86_ops functions. - -Signed-off-by: Konrad Rzeszutek Wilk -[v1: Changed x86_apic -> x86_ioapic per Yinghai Lu suggestion] -Acked-by: Suresh Siddha ---- - arch/x86/include/asm/io_apic.h | 40 +++++++++++++++++++++-------- - arch/x86/include/asm/x86_init.h | 8 ++++++ - arch/x86/kernel/apic/io_apic.c | 54 ++++---------------------------------- - arch/x86/kernel/setup.c | 2 +- - arch/x86/kernel/x86_init.c | 8 ++++++ - 5 files changed, 52 insertions(+), 60 deletions(-) - -diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h -index 190d8c2..ba1b11a 100644 ---- a/arch/x86/include/asm/io_apic.h -+++ b/arch/x86/include/asm/io_apic.h -@@ -5,6 +5,7 @@ - #include - #include - #include -+#include - - /* - * Intel IO-APIC support for SMP and UP systems. -@@ -21,15 +22,6 @@ - #define IO_APIC_REDIR_LEVEL_TRIGGER (1 << 15) - #define IO_APIC_REDIR_MASKED (1 << 16) - --struct io_apic_ops { -- void (*init)(void); -- unsigned int (*read)(unsigned int apic, unsigned int reg); -- void (*write)(unsigned int apic, unsigned int reg, unsigned int value); -- void (*modify)(unsigned int apic, unsigned int reg, unsigned int value); --}; -- --void __init set_io_apic_ops(const struct io_apic_ops *); -- - /* - * The structure of the IO-APIC: - */ -@@ -156,7 +148,6 @@ struct io_apic_irq_attr; - extern int io_apic_set_pci_routing(struct device *dev, int irq, - struct io_apic_irq_attr *irq_attr); - void setup_IO_APIC_irq_extra(u32 gsi); --extern void ioapic_and_gsi_init(void); - extern void ioapic_insert_resources(void); - - int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr); -@@ -185,12 +176,35 @@ extern void mp_save_irq(struct mpc_intsrc *m); - - extern void disable_ioapic_support(void); - -+ -+void __init native_ioapic_init_mappings(void); -+unsigned int native_ioapic_read(unsigned int apic, unsigned int reg); -+void native_ioapic_write(unsigned int apic, unsigned int reg, -+ unsigned int val); -+void native_ioapic_modify(unsigned int apic, unsigned int reg, -+ unsigned int val); -+ -+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) -+{ -+ return x86_ioapic.read(apic, reg); -+} -+ -+static inline void io_apic_write(unsigned int apic, unsigned int reg, -+ unsigned int value) -+{ -+ x86_ioapic.write(apic, reg, value); -+} -+ -+static inline void io_apic_modify(unsigned int apic, unsigned int reg, -+ unsigned int value) -+{ -+ x86_ioapic.modify(apic, reg, value); -+} - #else /* !CONFIG_X86_IO_APIC */ - - #define io_apic_assign_pci_irqs 0 - #define setup_ioapic_ids_from_mpc x86_init_noop - static const int timer_through_8259 = 0; --static inline void ioapic_and_gsi_init(void) { } - static inline void ioapic_insert_resources(void) { } - #define gsi_top (NR_IRQS_LEGACY) - static inline int mp_find_ioapic(u32 gsi) { return 0; } -@@ -212,6 +226,10 @@ static inline int restore_ioapic_entries(void) - - static inline void mp_save_irq(struct mpc_intsrc *m) { }; - static inline void disable_ioapic_support(void) { } -+#define native_ioapic_init_mappings NULL -+#define native_ioapic_read NULL -+#define native_ioapic_write NULL -+#define native_ioapic_modify NULL - #endif - - #endif /* _ASM_X86_IO_APIC_H */ -diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h -index 517d476..a3730cc 100644 ---- a/arch/x86/include/asm/x86_init.h -+++ b/arch/x86/include/asm/x86_init.h -@@ -182,10 +182,18 @@ struct x86_msi_ops { - void (*restore_msi_irqs)(struct pci_dev *dev, int irq); - }; - -+struct x86_ioapic_ops { -+ void (*init)(void); -+ unsigned int (*read)(unsigned int apic, unsigned int reg); -+ void (*write)(unsigned int apic, unsigned int reg, unsigned int value); -+ void (*modify)(unsigned int apic, unsigned int reg, unsigned int value); -+}; -+ - extern struct x86_init_ops x86_init; - extern struct x86_cpuinit_ops x86_cpuinit; - extern struct x86_platform_ops x86_platform; - extern struct x86_msi_ops x86_msi; -+extern struct x86_ioapic_ops x86_ioapic; - - extern void x86_init_noop(void); - extern void x86_init_uint_noop(unsigned int unused); -diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c -index bf120234..9a15d4b 100644 ---- a/arch/x86/kernel/apic/io_apic.c -+++ b/arch/x86/kernel/apic/io_apic.c -@@ -67,25 +67,6 @@ - #define for_each_irq_pin(entry, head) \ - for (entry = head; entry; entry = entry->next) - --static void __init __ioapic_init_mappings(void); --static unsigned int __io_apic_read(unsigned int apic, unsigned int reg); --static void __io_apic_write(unsigned int apic, unsigned int reg, -- unsigned int val); --static void __io_apic_modify(unsigned int apic, unsigned int reg, -- unsigned int val); -- --static struct io_apic_ops io_apic_ops = { -- .init = __ioapic_init_mappings, -- .read = __io_apic_read, -- .write = __io_apic_write, -- .modify = __io_apic_modify, --}; -- --void __init set_io_apic_ops(const struct io_apic_ops *ops) --{ -- io_apic_ops = *ops; --} -- - /* - * Is the SiS APIC rmw bug present ? - * -1 = don't know, 0 = no, 1 = yes -@@ -313,24 +294,6 @@ static void free_irq_at(unsigned int at, struct irq_cfg *cfg) - irq_free_desc(at); - } - --static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) --{ -- return io_apic_ops.read(apic, reg); --} -- --static inline void io_apic_write(unsigned int apic, unsigned int reg, -- unsigned int value) --{ -- io_apic_ops.write(apic, reg, value); --} -- --static inline void io_apic_modify(unsigned int apic, unsigned int reg, -- unsigned int value) --{ -- io_apic_ops.modify(apic, reg, value); --} -- -- - struct io_apic { - unsigned int index; - unsigned int unused[3]; -@@ -351,15 +314,15 @@ static inline void io_apic_eoi(unsigned int apic, unsigned int vector) - writel(vector, &io_apic->eoi); - } - --static unsigned int __io_apic_read(unsigned int apic, unsigned int reg) -+unsigned int native_ioapic_read(unsigned int apic, unsigned int reg) - { - struct io_apic __iomem *io_apic = io_apic_base(apic); - writel(reg, &io_apic->index); - return readl(&io_apic->data); - } - --static void __io_apic_write(unsigned int apic, unsigned int reg, -- unsigned int value) -+void native_ioapic_write(unsigned int apic, unsigned int reg, -+ unsigned int value) - { - struct io_apic __iomem *io_apic = io_apic_base(apic); - writel(reg, &io_apic->index); -@@ -372,8 +335,8 @@ static void __io_apic_write(unsigned int apic, unsigned int reg, - * - * Older SiS APIC requires we rewrite the index register - */ --static void __io_apic_modify(unsigned int apic, unsigned int reg, -- unsigned int value) -+void native_ioapic_modify(unsigned int apic, unsigned int reg, -+ unsigned int value) - { - struct io_apic __iomem *io_apic = io_apic_base(apic); - -@@ -3910,12 +3873,7 @@ static struct resource * __init ioapic_setup_resources(int nr_ioapics) - return res; - } - --void __init ioapic_and_gsi_init(void) --{ -- io_apic_ops.init(); --} -- --static void __init __ioapic_init_mappings(void) -+void __init native_ioapic_init_mappings(void) - { - unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; - struct resource *ioapic_res; -diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c -index d7d5099..7eaef1a 100644 ---- a/arch/x86/kernel/setup.c -+++ b/arch/x86/kernel/setup.c -@@ -1016,7 +1016,7 @@ void __init setup_arch(char **cmdline_p) - init_cpu_to_node(); - - init_apic_mappings(); -- ioapic_and_gsi_init(); -+ x86_ioapic.init(); - - kvm_guest_init(); - -diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c -index 947a06c..df870d3 100644 ---- a/arch/x86/kernel/x86_init.c -+++ b/arch/x86/kernel/x86_init.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -117,3 +118,10 @@ struct x86_msi_ops x86_msi = { - .teardown_msi_irqs = default_teardown_msi_irqs, - .restore_msi_irqs = default_restore_msi_irqs, - }; -+ -+struct x86_ioapic_ops x86_ioapic = { -+ .init = native_ioapic_init_mappings, -+ .read = native_ioapic_read, -+ .write = native_ioapic_write, -+ .modify = native_ioapic_modify, -+}; --- -1.7.7.5 - diff --git a/xen-x86-Implement-x86_apic_ops.patch b/xen-x86-Implement-x86_apic_ops.patch deleted file mode 100644 index 0963ecb25..000000000 --- a/xen-x86-Implement-x86_apic_ops.patch +++ /dev/null @@ -1,85 +0,0 @@ -Or rather just implement one different function as opposed -to the native one : the read function. - -We synthesize the values. - -Acked-by: Suresh Siddha -Signed-off-by: Konrad Rzeszutek Wilk ---- - arch/x86/xen/Makefile | 2 +- - arch/x86/xen/apic.c | 17 +++++++++++++++++ - arch/x86/xen/enlighten.c | 2 ++ - arch/x86/xen/xen-ops.h | 4 ++++ - 4 files changed, 24 insertions(+), 1 deletions(-) - create mode 100644 arch/x86/xen/apic.c - -diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile -index add2c2d..96ab2c0 100644 ---- a/arch/x86/xen/Makefile -+++ b/arch/x86/xen/Makefile -@@ -20,5 +20,5 @@ obj-$(CONFIG_EVENT_TRACING) += trace.o - obj-$(CONFIG_SMP) += smp.o - obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o - obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o --obj-$(CONFIG_XEN_DOM0) += vga.o -+obj-$(CONFIG_XEN_DOM0) += apic.o vga.o - obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o -diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c -new file mode 100644 -index 0000000..71ed91c ---- /dev/null -+++ b/arch/x86/xen/apic.c -@@ -0,0 +1,17 @@ -+#include -+#include -+ -+unsigned int xen_io_apic_read(unsigned apic, unsigned reg) -+{ -+ if (reg == 0x1) -+ return 0x00170020; -+ else if (reg == 0x0) -+ return apic << 24; -+ -+ return 0xff; -+} -+ -+void __init xen_init_apic(void) -+{ -+ x86_ioapic.read = xen_io_apic_read; -+} -diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c -index 0732326..93a03195 100644 ---- a/arch/x86/xen/enlighten.c -+++ b/arch/x86/xen/enlighten.c -@@ -1377,6 +1377,8 @@ asmlinkage void __init xen_start_kernel(void) - xen_start_info->console.domU.mfn = 0; - xen_start_info->console.domU.evtchn = 0; - -+ xen_init_apic(); -+ - /* Make sure ACS will be enabled */ - pci_request_acs(); - -diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h -index b095739..45c0c06 100644 ---- a/arch/x86/xen/xen-ops.h -+++ b/arch/x86/xen/xen-ops.h -@@ -92,11 +92,15 @@ struct dom0_vga_console_info; - - #ifdef CONFIG_XEN_DOM0 - void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size); -+void __init xen_init_apic(void); - #else - static inline void __init xen_init_vga(const struct dom0_vga_console_info *info, - size_t size) - { - } -+static inline void __init xen_init_apic(void) -+{ -+} - #endif - - /* Declare an asm function, along with symbols needed to make it --- -1.7.7.5 -