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