1443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* 2443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Driver for the NXP SAA7164 PCIe bridge 3443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 49b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> 5443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 6443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * This program is free software; you can redistribute it and/or modify 7443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * it under the terms of the GNU General Public License as published by 8443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * the Free Software Foundation; either version 2 of the License, or 9443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * (at your option) any later version. 10443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 11443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * This program is distributed in the hope that it will be useful, 12443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * but WITHOUT ANY WARRANTY; without even the implied warranty of 13443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 15443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * GNU General Public License for more details. 16443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 17443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * You should have received a copy of the GNU General Public License 18443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * along with this program; if not, write to the Free Software 19443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 21443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 22443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth#include <linux/wait.h> 23443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 24443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth#include "saa7164.h" 25443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 265faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabstatic int saa7164_cmd_alloc_seqno(struct saa7164_dev *dev) 27443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 28443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int i, ret = -1; 29443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 30443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&dev->lock); 31443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { 32443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (dev->cmds[i].inuse == 0) { 33443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[i].inuse = 1; 34443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[i].signalled = 0; 35443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[i].timeout = 0; 36443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = dev->cmds[i].seqno; 37443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth break; 38443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 39443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 40443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&dev->lock); 41443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 42443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 43443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 44443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 455faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabstatic void saa7164_cmd_free_seqno(struct saa7164_dev *dev, u8 seqno) 46443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 47443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&dev->lock); 48443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((dev->cmds[seqno].inuse == 1) && 49443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (dev->cmds[seqno].seqno == seqno)) { 50443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[seqno].inuse = 0; 51443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[seqno].signalled = 0; 52443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[seqno].timeout = 0; 53443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 54443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&dev->lock); 55443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 56443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 575faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabstatic void saa7164_cmd_timeout_seqno(struct saa7164_dev *dev, u8 seqno) 58443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 59443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&dev->lock); 60443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((dev->cmds[seqno].inuse == 1) && 61443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (dev->cmds[seqno].seqno == seqno)) { 62443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[seqno].timeout = 1; 63443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 64443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&dev->lock); 65443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 66443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 675faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabstatic u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno) 68443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 69443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret = 0; 70443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 71443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&dev->lock); 72443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((dev->cmds[seqno].inuse == 1) && 73443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (dev->cmds[seqno].seqno == seqno)) { 74443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = dev->cmds[seqno].timeout; 75443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 76443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&dev->lock); 77443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 78443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 79443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 80443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 81443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* Commands to the f/w get marshelled to/from this code then onto the PCI 82443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * -bus/c running buffer. */ 8339e469ab6dee0977a6fb632c711fba1ec5fca401Steven Tothint saa7164_irq_dequeue(struct saa7164_dev *dev) 8439e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth{ 854a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth int ret = SAA_OK, i = 0; 8639e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth u32 timeout; 8761ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe wait_queue_head_t *q = NULL; 884a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth u8 tmp[512]; 8939e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth dprintk(DBGLVL_CMD, "%s()\n", __func__); 9039e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth 9139e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth /* While any outstand message on the bus exists... */ 9239e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth do { 9339e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth 9439e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth /* Peek the msg bus */ 954d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 }; 9639e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth ret = saa7164_bus_get(dev, &tRsp, NULL, 1); 9739e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth if (ret != SAA_OK) 9839e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth break; 9939e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth 10039e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth q = &dev->cmds[tRsp.seqno].wait; 10139e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno); 10239e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout); 10339e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth if (!timeout) { 10439e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth dprintk(DBGLVL_CMD, 10539e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth "%s() signalled seqno(%d) (for dequeue)\n", 10639e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth __func__, tRsp.seqno); 10739e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth dev->cmds[tRsp.seqno].signalled = 1; 10839e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth wake_up(q); 10939e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth } else { 11039e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth printk(KERN_ERR 11139e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth "%s() found timed out command on the bus\n", 11239e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth __func__); 1134a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth 1144a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth /* Clean the bus */ 1154a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth ret = saa7164_bus_get(dev, &tRsp, &tmp, 0); 1164a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth printk(KERN_ERR "%s() ret = %x\n", __func__, ret); 1174a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth if (ret == SAA_ERR_EMPTY) 1184a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth /* Someone else already fetched the response */ 1194a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth return SAA_OK; 1204a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth 1214a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth if (ret != SAA_OK) 1224a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth return ret; 12339e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth } 1244a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth 125bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth /* It's unlikely to have more than 4 or 5 pending messages, 126bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth * ensure we exit at some point regardless. 1274a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth */ 1284a52be0faa014380b7bf15c5ca7e3dea7cb4ea52Steven Toth } while (i++ < 32); 12939e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth 13039e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth return ret; 13139e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth} 13239e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth 13339e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth/* Commands to the f/w get marshelled to/from this code then onto the PCI 13439e469ab6dee0977a6fb632c711fba1ec5fca401Steven Toth * -bus/c running buffer. */ 1355faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabstatic int saa7164_cmd_dequeue(struct saa7164_dev *dev) 136443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 137443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int loop = 1; 138443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret; 139443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u32 timeout; 14061ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe wait_queue_head_t *q = NULL; 141443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u8 tmp[512]; 142443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s()\n", __func__); 143443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 144443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth while (loop) { 145443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 1464d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 }; 147443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_bus_get(dev, &tRsp, NULL, 1); 148443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret == SAA_ERR_EMPTY) 149443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_OK; 150443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 151443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) 152443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 153443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 154443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth q = &dev->cmds[tRsp.seqno].wait; 155443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth timeout = saa7164_cmd_timeout_get(dev, tRsp.seqno); 156443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() timeout = %d\n", __func__, timeout); 157443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (timeout) { 158443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "found timed out command on the bus\n"); 159443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 160443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Clean the bus */ 161443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_bus_get(dev, &tRsp, &tmp, 0); 162443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "ret = %x\n", ret); 163443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret == SAA_ERR_EMPTY) 164443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Someone else already fetched the response */ 165443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_OK; 166443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 167443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) 168443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 169443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 170443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (tRsp.flags & PVC_CMDFLAG_CONTINUE) 171443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "split response\n"); 172443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 173443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_cmd_free_seqno(dev, tRsp.seqno); 174443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 175443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR " timeout continue\n"); 176443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth continue; 177443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 178443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 179443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() signalled seqno(%d) (for dequeue)\n", 180443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, tRsp.seqno); 181443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[tRsp.seqno].signalled = 1; 182443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth wake_up(q); 183443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_OK; 184443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 185443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 186443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_OK; 187443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 188443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 1895faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabstatic int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg, 1905faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehab void *buf) 191443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 1924d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResBusInfo *bus = &dev->bus; 193443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u8 cmd_sent; 194443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u16 size, idx; 195443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u32 cmds; 196443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth void *tmp; 197443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret = -1; 198443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 199443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (!msg) { 200443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() !msg\n", __func__); 201443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BAD_PARAMETER; 202443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 203443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 204443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&dev->cmds[msg->id].lock); 205443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 206443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth size = msg->size; 207443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth idx = 0; 208443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth cmds = size / bus->m_wMaxReqSize; 209443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (size % bus->m_wMaxReqSize == 0) 210443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth cmds -= 1; 211443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 212443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth cmd_sent = 0; 213443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 214443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Split the request into smaller chunks */ 215443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth for (idx = 0; idx < cmds; idx++) { 216443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 217443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->flags |= SAA_CMDFLAG_CONTINUE; 218443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->size = bus->m_wMaxReqSize; 219443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth tmp = buf + idx * bus->m_wMaxReqSize; 220443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 221443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_bus_set(dev, msg, tmp); 222443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 223443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() set failed %d\n", __func__, ret); 224443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 225443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (cmd_sent) { 226443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_BUSY; 227443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 228443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 229443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_OVERFLOW; 230443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 231443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 232443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth cmd_sent = 1; 233443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 234443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 235443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* If not the last command... */ 236443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (idx != 0) 237443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->flags &= ~SAA_CMDFLAG_CONTINUE; 238443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 239443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->size = size - idx * bus->m_wMaxReqSize; 240443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 241443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_bus_set(dev, msg, buf + idx * bus->m_wMaxReqSize); 242443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 243443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() set last failed %d\n", __func__, ret); 244443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 245443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (cmd_sent) { 246443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_BUSY; 247443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 248443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 249443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_OVERFLOW; 250443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 251443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 252443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_OK; 253443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 254443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothout: 255443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&dev->cmds[msg->id].lock); 256443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 257443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 258443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 259443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* Wait for a signal event, without holding a mutex. Either return TIMEOUT if 26025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * the event never occurred, or SAA_OK if it was signaled during the wait. 261443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 2625faf7db804e1e67ab8f78edb305d1858779a6279Mauro Carvalho Chehabstatic int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) 263443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 26461ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe wait_queue_head_t *q = NULL; 265443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret = SAA_BUS_TIMEOUT; 266443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth unsigned long stamp; 267443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int r; 268443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 269b1912a85b54c27738afe1c4fa069df02d3316f0cIngo Molnar if (saa_debug >= 4) 270443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_bus_dump(dev); 271443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 272443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s(seqno=%d)\n", __func__, seqno); 273443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 274443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&dev->lock); 275443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((dev->cmds[seqno].inuse == 1) && 276443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (dev->cmds[seqno].seqno == seqno)) { 277443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth q = &dev->cmds[seqno].wait; 278443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 279443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&dev->lock); 280443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 281443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (q) { 282443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* If we haven't been signalled we need to wait */ 283443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (dev->cmds[seqno].signalled == 0) { 284443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth stamp = jiffies; 285443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, 286443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "%s(seqno=%d) Waiting (signalled=%d)\n", 287443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, seqno, dev->cmds[seqno].signalled); 288443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 289443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Wait for signalled to be flagged or timeout */ 290bbf504c37ddced9957fa65aac9a213f322871b07Steven Toth /* In a highly stressed system this can easily extend 291bbf504c37ddced9957fa65aac9a213f322871b07Steven Toth * into multiple seconds before the deferred worker 292bbf504c37ddced9957fa65aac9a213f322871b07Steven Toth * is scheduled, and we're woken up via signal. 293bbf504c37ddced9957fa65aac9a213f322871b07Steven Toth * We typically are signalled in < 50ms but it can 294bbf504c37ddced9957fa65aac9a213f322871b07Steven Toth * take MUCH longer. 295bbf504c37ddced9957fa65aac9a213f322871b07Steven Toth */ 296bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth wait_event_timeout(*q, dev->cmds[seqno].signalled, 297bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth (HZ * waitsecs)); 298dd1ee4442d14f90d4da6b8a2ee37ab922100f250Steven Toth r = time_before(jiffies, stamp + (HZ * waitsecs)); 299443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (r) 300443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_OK; 301443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 302443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_cmd_timeout_seqno(dev, seqno); 303443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 304443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s(seqno=%d) Waiting res = %d " 305443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "(signalled=%d)\n", __func__, seqno, r, 306443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[seqno].signalled); 307443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else 308443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_OK; 309443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else 310443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s(seqno=%d) seqno is invalid\n", 311443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, seqno); 312443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 313443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 314443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 315443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 316443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothvoid saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno) 317443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 318443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int i; 319443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s()\n", __func__); 320443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 321443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&dev->lock); 322443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { 323443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (dev->cmds[i].inuse == 1) { 324443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, 325443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "seqno %d inuse, sig = %d, t/out = %d\n", 326443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[i].seqno, 327443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[i].signalled, 328443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[i].timeout); 329443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 330443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 331443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 332443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { 333443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((dev->cmds[i].inuse == 1) && ((i == 0) || 334443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (dev->cmds[i].signalled) || (dev->cmds[i].timeout))) { 335443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s(seqno=%d) calling wake_up\n", 336443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, i); 337443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dev->cmds[i].signalled = 1; 338443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth wake_up(&dev->cmds[i].wait); 339443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 340443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 341443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&dev->lock); 342443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 343443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 3444d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehabint saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, 345443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u16 controlselector, u16 size, void *buf) 346443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 3474d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResInfo command_t, *pcommand_t; 3484d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResInfo response_t, *presponse_t; 349443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u8 errdata[256]; 350443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u16 resp_dsize; 351443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u16 data_recd; 352443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u32 loop; 353443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret; 354443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int safety = 0; 355443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 356443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s(unitid = %s (%d) , command = 0x%x, " 357443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "sel = 0x%x)\n", __func__, saa7164_unitid_name(dev, id), id, 358443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth command, controlselector); 359443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 36061ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe if ((size == 0) || (buf == NULL)) { 361443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Invalid param\n", __func__); 362443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BAD_PARAMETER; 363443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 364443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 365443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Prepare some basic command/response structures */ 366443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memset(&command_t, 0, sizeof(command_t)); 3677157fbd0ed1a00024fb915cfa5ed93fb4ce9dfafJean Delvare memset(&response_t, 0, sizeof(response_t)); 368443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth pcommand_t = &command_t; 369443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth presponse_t = &response_t; 370443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth command_t.id = id; 371443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth command_t.command = command; 372443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth command_t.controlselector = controlselector; 373443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth command_t.size = size; 374443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 375443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Allocate a unique sequence number */ 376443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_cmd_alloc_seqno(dev); 377443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret < 0) { 378443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() No free sequences\n", __func__); 379443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_NO_RESOURCES; 380443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 381443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 382443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 383443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth command_t.seqno = (u8)ret; 384443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 385443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Send Command */ 386443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth resp_dsize = size; 387443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth pcommand_t->size = size; 388443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 389443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() pcommand_t.seqno = %d\n", 390443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, pcommand_t->seqno); 391443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 392443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() pcommand_t.size = %d\n", 393443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, pcommand_t->size); 394443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 395443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_cmd_set(dev, pcommand_t, buf); 396443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 397443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() set command failed %d\n", __func__, ret); 398443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 399443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_ERR_BUSY) 400443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_cmd_free_seqno(dev, pcommand_t->seqno); 401443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 402443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Flag a timeout, because at least one 403443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * command was sent */ 404443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno); 405443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 406443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 407443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 408443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 409443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* With split responses we have to collect the msgs piece by piece */ 410443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth data_recd = 0; 411443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth loop = 1; 412443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth while (loop) { 413443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() loop\n", __func__); 414443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 415443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_cmd_wait(dev, pcommand_t->seqno); 416443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() loop ret = %d\n", __func__, ret); 417443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 418443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* if power is down and this is not a power command ... */ 419443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 420443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret == SAA_BUS_TIMEOUT) { 421443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "Event timed out\n"); 422443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_cmd_timeout_seqno(dev, pcommand_t->seqno); 423443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 424443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 425443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 426443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 427443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "spurious error\n"); 428443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 429443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 430443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 431443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Peek response */ 432443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_bus_get(dev, presponse_t, NULL, 1); 433443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret == SAA_ERR_EMPTY) { 434443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(4, "%s() SAA_ERR_EMPTY\n", __func__); 435443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth continue; 436443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 437443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 438443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "peek failed\n"); 439443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 440443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 441443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 442443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() presponse_t->seqno = %d\n", 443443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, presponse_t->seqno); 444443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 445443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() presponse_t->flags = 0x%x\n", 446443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, presponse_t->flags); 447443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 448443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() presponse_t->size = %d\n", 449443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, presponse_t->size); 450443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 451443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Check if the response was for our command */ 452443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (presponse_t->seqno != pcommand_t->seqno) { 453443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 454443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, 455443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "wrong event: seqno = %d, " 456443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "expected seqno = %d, " 457443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "will dequeue regardless\n", 458443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth presponse_t->seqno, pcommand_t->seqno); 459443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 460443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_cmd_dequeue(dev); 461443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 462443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "dequeue failed, ret = %d\n", 463443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret); 464443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (safety++ > 16) { 465443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR 466443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "dequeue exceeded, safety exit\n"); 467443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BUSY; 468443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 469443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 470443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 471443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth continue; 472443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 473443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 474443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((presponse_t->flags & PVC_RESPONSEFLAG_ERROR) != 0) { 475443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 476443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memset(&errdata[0], 0, sizeof(errdata)); 477443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 478443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_bus_get(dev, presponse_t, &errdata[0], 0); 479443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 480443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "get error(2)\n"); 481443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 482443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 483443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 484443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_cmd_free_seqno(dev, pcommand_t->seqno); 485443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 486443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() errdata %02x%02x%02x%02x\n", 487443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, errdata[0], errdata[1], errdata[2], 488443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth errdata[3]); 489443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 490443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Map error codes */ 491443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() cmd, error code = 0x%x\n", 492443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, errdata[0]); 493443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 494443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth switch (errdata[0]) { 495443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth case PVC_ERRORCODE_INVALID_COMMAND: 496443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() INVALID_COMMAND\n", 497443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__); 498443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_INVALID_COMMAND; 499443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth break; 500443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth case PVC_ERRORCODE_INVALID_DATA: 501443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() INVALID_DATA\n", 502443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__); 503443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_BAD_PARAMETER; 504443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth break; 505443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth case PVC_ERRORCODE_TIMEOUT: 506443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() TIMEOUT\n", __func__); 507443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_TIMEOUT; 508443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth break; 509443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth case PVC_ERRORCODE_NAK: 510443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() NAK\n", __func__); 511443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_NULL_PACKET; 512443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth break; 513443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth case PVC_ERRORCODE_UNKNOWN: 514443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth case PVC_ERRORCODE_INVALID_CONTROL: 515443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, 516443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "%s() UNKNOWN OR INVALID CONTROL\n", 517443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__); 518443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth default: 519443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() UNKNOWN\n", __func__); 520443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_NOT_SUPPORTED; 521443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 522443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 523443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* See of other commands are on the bus */ 524443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (saa7164_cmd_dequeue(dev) != SAA_OK) 525443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "dequeue(2) failed\n"); 526443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 527443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 528443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 529443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 530443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* If response is invalid */ 531443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((presponse_t->id != pcommand_t->id) || 532443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (presponse_t->command != pcommand_t->command) || 533443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (presponse_t->controlselector != 534443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth pcommand_t->controlselector) || 535443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (((resp_dsize - data_recd) != presponse_t->size) && 536443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth !(presponse_t->flags & PVC_CMDFLAG_CONTINUE)) || 537443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ((resp_dsize - data_recd) < presponse_t->size)) { 538443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 539443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Invalid */ 540443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() Invalid\n", __func__); 54161ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe ret = saa7164_bus_get(dev, presponse_t, NULL, 0); 542443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 543443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "get failed\n"); 544443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 545443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 546443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 547443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* See of other commands are on the bus */ 548443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (saa7164_cmd_dequeue(dev) != SAA_OK) 549443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "dequeue(3) failed\n"); 550443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth continue; 551443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 552443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 553443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* OK, now we're actually getting out correct response */ 554443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = saa7164_bus_get(dev, presponse_t, buf + data_recd, 0); 555443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (ret != SAA_OK) { 556443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "get failed\n"); 557443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 558443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 559443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 560443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth data_recd = presponse_t->size + data_recd; 561443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (resp_dsize == data_recd) { 562443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() Resp recd\n", __func__); 563443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth break; 564443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 565443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 566443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* See of other commands are on the bus */ 567443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (saa7164_cmd_dequeue(dev) != SAA_OK) 568443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "dequeue(3) failed\n"); 569443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 570443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth continue; 571443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 572443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } /* (loop) */ 573443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 574443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Release the sequence number allocation */ 575443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_cmd_free_seqno(dev, pcommand_t->seqno); 576443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 577443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* if powerdown signal all pending commands */ 578443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 579443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_CMD, "%s() Calling dequeue then exit\n", __func__); 580443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 581443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* See of other commands are on the bus */ 582443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (saa7164_cmd_dequeue(dev) != SAA_OK) 583443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "dequeue(4) failed\n"); 584443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 585443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_OK; 586443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothout: 587443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 588443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 589443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 590