saa7164-bus.c revision 9b8b0199b86eaa595e3ccacb413e955a193f1962
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 "saa7164.h" 23443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 24443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* The message bus to/from the firmware is a ring buffer in PCI address 25443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * space. Establish the defaults. 26443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 27443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothint saa7164_bus_setup(struct saa7164_dev *dev) 28443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 29443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth tmComResBusInfo_t *b = &dev->bus; 30443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 31443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_init(&b->lock); 32443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 33443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->Type = TYPE_BUS_PCIe; 34443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE; 35443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 36443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwSetRing = (u8 *)(dev->bmmio + 37443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ((u32)dev->busdesc.CommandRing)); 38443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 39443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE; 40443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 41443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwGetRing = (u8 *)(dev->bmmio + 42443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ((u32)dev->busdesc.ResponseRing)); 43443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 44443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE; 45443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 46443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwSetWritePos = (u32 *)((u8 *)(dev->bmmio + 47443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64)))); 48443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 49443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwSetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos + 50443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 1 * sizeof(u32)); 51443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 52443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwGetWritePos = (u32 *)((u8 *)b->m_pdwSetWritePos + 53443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 2 * sizeof(u32)); 54443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 55443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwGetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos + 56443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 3 * sizeof(u32)); 57443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 58443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return 0; 59443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 60443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 61443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothvoid saa7164_bus_dump(struct saa7164_dev *dev) 62443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 63443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth tmComResBusInfo_t *b = &dev->bus; 64443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 65443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "Dumping the bus structure:\n"); 66443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .type = %d\n", b->Type); 67443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .dev->bmmio = 0x%p\n", dev->bmmio); 68443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_wMaxReqSize = 0x%x\n", b->m_wMaxReqSize); 69443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_pdwSetRing = 0x%p\n", b->m_pdwSetRing); 70443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_dwSizeSetRing = 0x%x\n", b->m_dwSizeSetRing); 71443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing); 72443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing); 73443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 74443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_pdwSetWritePos = 0x%p (0x%08x)\n", 75443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwSetWritePos, *b->m_pdwSetWritePos); 76443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 77443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_pdwSetReadPos = 0x%p (0x%08x)\n", 78443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwSetReadPos, *b->m_pdwSetReadPos); 79443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 80443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_pdwGetWritePos = 0x%p (0x%08x)\n", 81443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwGetWritePos, *b->m_pdwGetWritePos); 82443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 83443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_pdwGetReadPos = 0x%p (0x%08x)\n", 84443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwGetReadPos, *b->m_pdwGetReadPos); 85443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 86443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 87443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothvoid saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf) 88443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 89443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "Dumping msg structure:\n"); 90443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .id = %d\n", m->id); 91443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .flags = 0x%x\n", m->flags); 92443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .size = 0x%x\n", m->size); 93443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .command = 0x%x\n", m->command); 94443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .controlselector = 0x%x\n", m->controlselector); 95443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .seqno = %d\n", m->seqno); 96443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) 97443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .buffer (ignored)\n"); 98443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 99443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 100443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* 101443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Places a command or a response on the bus. The implementation does not 102443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * know if it is a command or a response it just places the data on the 103443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * bus depending on the bus information given in the tmComResBusInfo_t 104443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * structure. If the command or response does not fit into the bus ring 105443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * buffer it will be refused. 106443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 107443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Return Value: 108443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * SAA_OK The function executed successfully. 109443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * < 0 One or more members are not initialized. 110443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 111443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothint saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf) 112443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 113443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth tmComResBusInfo_t *bus = &dev->bus; 114443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u32 bytes_to_write, read_distance, timeout, curr_srp, curr_swp; 115443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u32 new_swp, space_rem; 116443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret = SAA_ERR_BAD_PARAMETER; 117443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 118443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (!msg) { 119443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() !msg\n", __func__); 120443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BAD_PARAMETER; 121443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 122443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 123443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s()\n", __func__); 124443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 125443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->size = cpu_to_le16(msg->size); 126443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->command = cpu_to_le16(msg->command); 127443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->controlselector = cpu_to_le16(msg->controlselector); 128443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 129443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (msg->size > dev->bus.m_wMaxReqSize) { 130443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", 131443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__); 132443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BAD_PARAMETER; 133443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 134443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 135443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((msg->size > 0) && (buf == 0)) { 136443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Missing message buffer\n", __func__); 137443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BAD_PARAMETER; 138443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 139443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 140443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Lock the bus from any other access */ 141443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&bus->lock); 142443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 143443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_write = sizeof(*msg) + msg->size; 144443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth read_distance = 0; 145443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth timeout = SAA_BUS_TIMEOUT; 146443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos); 147443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth curr_swp = le32_to_cpu(*bus->m_pdwSetWritePos); 148443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 149443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Deal with ring wrapping issues */ 150443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_srp > curr_swp) 151443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* The ring has not wrapped yet */ 152443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth read_distance = curr_srp - curr_swp; 153443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 154443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Deal with the wrapped ring */ 155443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth read_distance = (curr_srp + bus->m_dwSizeSetRing) - curr_swp; 156443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 157443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__, 158443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_write); 159443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 160443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() read_distance = %d\n", __func__, 161443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth read_distance); 162443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 163443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp); 164443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp); 165443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 166443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Process the msg and write the content onto the bus */ 167443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth while (bytes_to_write >= read_distance) { 168443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 169443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (timeout-- == 0) { 170443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() bus timeout\n", __func__); 171443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_NO_RESOURCES; 172443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 173443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 174443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 175443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* TODO: Review this delay, efficient? */ 176443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Wait, allowing the hardware fetch time */ 177443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mdelay(1); 178443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 179443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Check the space usage again */ 180443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos); 181443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 182443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Deal with ring wrapping issues */ 183443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_srp > curr_swp) 184443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Read didn't wrap around the buffer */ 185443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth read_distance = curr_srp - curr_swp; 186443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 187443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Deal with the wrapped ring */ 188443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth read_distance = (curr_srp + bus->m_dwSizeSetRing) - 189443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth curr_swp; 190443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 191443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 192443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 193443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate the new write position */ 194443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_swp = curr_swp + bytes_to_write; 195443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 196443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); 197443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__, 198443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bus->m_dwSizeSetRing); 199443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 200443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Mental Note: line 462 tmmhComResBusPCIe.cpp */ 201443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 202443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Check if we're going to wrap again */ 203443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (new_swp > bus->m_dwSizeSetRing) { 204443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 205443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Ring wraps */ 206443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_swp -= bus->m_dwSizeSetRing; 207443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 208443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem = bus->m_dwSizeSetRing - curr_swp; 209443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 210443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__, 211443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem); 212443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 213207b42c492cc335806957c139381eb260a808837Steven Toth dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__, 214207b42c492cc335806957c139381eb260a808837Steven Toth (u32)sizeof(*msg)); 215443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 216443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (space_rem < sizeof(*msg)) { 217443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() tr4\n", __func__); 218443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 219443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Split the msg into pieces as the ring wraps */ 220443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem); 221443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem, 222443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg) - space_rem); 223443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 224443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem, 225443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth buf, msg->size); 226443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 227443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else if (space_rem == sizeof(*msg)) { 228443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() tr5\n", __func__); 229443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 230443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Additional data at the beginning of the ring */ 231443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 232443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing, buf, msg->size); 233443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 234443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else { 235443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Additional data wraps around the ring */ 236443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 237443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (msg->size > 0) { 238443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing + curr_swp + 239443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg), buf, space_rem - 240443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg)); 241443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing, (u8 *)buf + 242443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem - sizeof(*msg), 243443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_write - space_rem); 244443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 245443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 246443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 247443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 248443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } /* (new_swp > bus->m_dwSizeSetRing) */ 249443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else { 250443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() tr6\n", __func__); 251443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 252443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* The ring buffer doesn't wrap, two simple copies */ 253443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 254443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf, 255443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->size); 256443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 257443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 258443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); 259443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 2601a6450d4d43a4d4caecaa3ca7796cbe8c7cfbba3Steven Toth /* TODO: Convert all of the direct PCI writes into 261443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * saa7164_writel/b calls for consistency. 262443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 263443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 264443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Update the bus write position */ 265443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth *bus->m_pdwSetWritePos = cpu_to_le32(new_swp); 266443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_OK; 267443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 268443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothout: 269443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&bus->lock); 270443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 271443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 272443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 273443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* 274443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Receive a command or a response from the bus. The implementation does not 275443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * know if it is a command or a response it simply dequeues the data, 276443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * depending on the bus information given in the tmComResBusInfo_t structure. 277443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 278443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Return Value: 279443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 0 The function executed successfully. 280443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * < 0 One or more members are not initialized. 281443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 282443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothint saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf, 283443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int peekonly) 284443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 285443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth tmComResBusInfo_t *bus = &dev->bus; 286443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u32 bytes_to_read, write_distance, curr_grp, curr_gwp, 287443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp, buf_size, space_rem; 288443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth tmComResInfo_t msg_tmp; 289443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret = SAA_ERR_BAD_PARAMETER; 290443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 291443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (msg == 0) 292443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 293443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 294443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (msg->size > dev->bus.m_wMaxReqSize) { 295443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", 296443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__); 297443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 298443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 299443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 300443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((peekonly == 0) && (msg->size > 0) && (buf == 0)) { 301443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR 302443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "%s() Missing msg buf, size should be %d bytes\n", 303443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, msg->size); 304443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 305443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 306443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 307443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&bus->lock); 308443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 309443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Peek the bus to see if a msg exists, if it's not what we're expecting 310443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * then return cleanly else read the message from the bus. 311443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 312443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth curr_gwp = le32_to_cpu(*bus->m_pdwGetWritePos); 313443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth curr_grp = le32_to_cpu(*bus->m_pdwGetReadPos); 314443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 315443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_gwp == curr_grp) { 316443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() No message on the bus\n", __func__); 317443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_EMPTY; 318443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 319443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 320443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 321443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_read = sizeof(*msg); 322443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 323443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate write distance to current read position */ 324443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = 0; 325443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_gwp >= curr_grp) 326443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Write doesn't wrap around the ring */ 327443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = curr_gwp - curr_grp; 328443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 329443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Write wraps around the ring */ 330443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; 331443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 332443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (bytes_to_read > write_distance) { 333443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() No message/response found\n", __func__); 334443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_INVALID_COMMAND; 335443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 336443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 337443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 338443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate the new read position */ 339443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp = curr_grp + bytes_to_read; 340443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (new_grp > bus->m_dwSizeGetRing) { 341443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 342443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Ring wraps */ 343443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp -= bus->m_dwSizeGetRing; 344443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem = bus->m_dwSizeGetRing - curr_grp; 345443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 346443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem); 347443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing, 348443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_read - space_rem); 349443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 350443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else { 351443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* No wrapping */ 352443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read); 353443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 354443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 355443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* No need to update the read positions, because this was a peek */ 356443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* If the caller specifically want to peek, return */ 357443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (peekonly) { 358443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(msg, &msg_tmp, sizeof(*msg)); 359443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto peekout; 360443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 361443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 362443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Check if the command/response matches what is expected */ 363443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) || 364443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (msg_tmp.controlselector != msg->controlselector) || 365443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) { 366443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 367443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__); 368443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_bus_dumpmsg(dev, msg, buf); 369443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_bus_dumpmsg(dev, &msg_tmp, 0); 370443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_INVALID_COMMAND; 371443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 372443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 373443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 374443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Get the actual command and response from the bus */ 375443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth buf_size = msg->size; 376443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 377443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_read = sizeof(*msg) + msg->size; 378443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate write distance to current read position */ 379443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = 0; 380443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_gwp >= curr_grp) 381443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Write doesn't wrap around the ring */ 382443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = curr_gwp - curr_grp; 383443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 384443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Write wraps around the ring */ 385443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; 386443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 387443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (bytes_to_read > write_distance) { 388443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Invalid bus state, missing msg " 389443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "or mangled ring, faulty H/W / bad code?\n", __func__); 390443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_INVALID_COMMAND; 391443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 392443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 393443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 394443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate the new read position */ 395443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp = curr_grp + bytes_to_read; 396443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (new_grp > bus->m_dwSizeGetRing) { 397443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 398443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Ring wraps */ 399443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp -= bus->m_dwSizeGetRing; 400443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem = bus->m_dwSizeGetRing - curr_grp; 401443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 402443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (space_rem < sizeof(*msg)) { 403443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* msg wraps around the ring */ 404443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem); 405443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing, 406443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg) - space_rem); 407443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) 408443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) - 409443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem, buf_size); 410443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 411443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else if (space_rem == sizeof(*msg)) { 412443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 413443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) 414443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(buf, bus->m_pdwGetRing, buf_size); 415443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else { 416443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Additional data wraps around the ring */ 417443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 418443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) { 419443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(buf, bus->m_pdwGetRing + curr_grp + 420443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg), space_rem - sizeof(*msg)); 421443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(buf + space_rem - sizeof(*msg), 422443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bus->m_pdwGetRing, bytes_to_read - 423443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem); 424443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 425443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 426443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 427443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 428443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else { 429443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* No wrapping */ 430443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 431443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) 432443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), 433443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth buf_size); 434443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 435443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 436443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Update the read positions, adjusting the ring */ 437443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth *bus->m_pdwGetReadPos = cpu_to_le32(new_grp); 438443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 439443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothpeekout: 440443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->size = le16_to_cpu(msg->size); 441443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->command = le16_to_cpu(msg->command); 442443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->controlselector = le16_to_cpu(msg->controlselector); 443443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_OK; 444443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothout: 445443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&bus->lock); 446443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 447443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 448443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 449