File Index
Files and directories
Sign in
FILE

io.c

File preview with syntax highlighting.

linux-6.19.14/arch/parisc/lib/io.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * arch/parisc/lib/io.c
  4 *
  5 * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
  6 * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
  7 *
  8 * IO accessing functions which shouldn't be inlined because they're too big
  9 */
 10
 11#include <linux/kernel.h>
 12#include <linux/module.h>
 13#include <asm/io.h>
 14
 15/*
 16 * Read COUNT 8-bit bytes from port PORT into memory starting at
 17 * SRC.
 18 */
 19void insb (unsigned long port, void *dst, unsigned long count)
 20{
 21	unsigned char *p;
 22
 23	p = (unsigned char *)dst;
 24
 25	while (((unsigned long)p) & 0x3) {
 26		if (!count)
 27			return;
 28		count--;
 29		*p = inb(port);
 30		p++;
 31	}
 32
 33	while (count >= 4) {
 34		unsigned int w;
 35		count -= 4;
 36		w = inb(port) << 24;
 37		w |= inb(port) << 16;
 38		w |= inb(port) << 8;
 39		w |= inb(port);
 40		*(unsigned int *) p = w;
 41		p += 4;
 42	}
 43
 44	while (count) {
 45		--count;
 46		*p = inb(port);
 47		p++;
 48	}
 49}
 50
 51
 52/*
 53 * Read COUNT 16-bit words from port PORT into memory starting at
 54 * SRC.  SRC must be at least short aligned.  This is used by the
 55 * IDE driver to read disk sectors.  Performance is important, but
 56 * the interfaces seems to be slow: just using the inlined version
 57 * of the inw() breaks things.
 58 */
 59void insw (unsigned long port, void *dst, unsigned long count)
 60{
 61	unsigned int l = 0, l2;
 62	unsigned char *p;
 63
 64	p = (unsigned char *)dst;
 65
 66	if (!count)
 67		return;
 68
 69	switch (((unsigned long)p) & 0x3)
 70	{
 71	 case 0x00:			/* Buffer 32-bit aligned */
 72		while (count>=2) {
 73
 74			count -= 2;
 75			l = cpu_to_le16(inw(port)) << 16;
 76			l |= cpu_to_le16(inw(port));
 77			*(unsigned int *)p = l;
 78			p += 4;
 79		}
 80		if (count) {
 81			*(unsigned short *)p = cpu_to_le16(inw(port));
 82		}
 83		break;
 84
 85	 case 0x02:			/* Buffer 16-bit aligned */
 86		*(unsigned short *)p = cpu_to_le16(inw(port));
 87		p += 2;
 88		count--;
 89		while (count>=2) {
 90
 91			count -= 2;
 92			l = cpu_to_le16(inw(port)) << 16;
 93			l |= cpu_to_le16(inw(port));
 94			*(unsigned int *)p = l;
 95			p += 4;
 96		}
 97		if (count) {
 98			*(unsigned short *)p = cpu_to_le16(inw(port));
 99		}
100		break;
101
102	 case 0x01:			/* Buffer 8-bit aligned */
103	 case 0x03:
104		/* I don't bother with 32bit transfers
105		 * in this case, 16bit will have to do -- DE */
106		--count;
107
108		l = cpu_to_le16(inw(port));
109		*p = l >> 8;
110		p++;
111		while (count--)
112		{
113			l2 = cpu_to_le16(inw(port));
114			*(unsigned short *)p = (l & 0xff) << 8 | (l2 >> 8);
115			p += 2;
116			l = l2;
117		}
118		*p = l & 0xff;
119		break;
120	}
121}
122
123
124
125/*
126 * Read COUNT 32-bit words from port PORT into memory starting at
127 * SRC. Now works with any alignment in SRC. Performance is important,
128 * but the interfaces seems to be slow: just using the inlined version
129 * of the inl() breaks things.
130 */
131void insl (unsigned long port, void *dst, unsigned long count)
132{
133	unsigned int l = 0, l2;
134	unsigned char *p;
135
136	p = (unsigned char *)dst;
137
138	if (!count)
139		return;
140
141	switch (((unsigned long) dst) & 0x3)
142	{
143	 case 0x00:			/* Buffer 32-bit aligned */
144		while (count--)
145		{
146			*(unsigned int *)p = cpu_to_le32(inl(port));
147			p += 4;
148		}
149		break;
150
151	 case 0x02:			/* Buffer 16-bit aligned */
152		--count;
153
154		l = cpu_to_le32(inl(port));
155		*(unsigned short *)p = l >> 16;
156		p += 2;
157
158		while (count--)
159		{
160			l2 = cpu_to_le32(inl(port));
161			*(unsigned int *)p = (l & 0xffff) << 16 | (l2 >> 16);
162			p += 4;
163			l = l2;
164		}
165		*(unsigned short *)p = l & 0xffff;
166		break;
167	 case 0x01:			/* Buffer 8-bit aligned */
168		--count;
169
170		l = cpu_to_le32(inl(port));
171		*(unsigned char *)p = l >> 24;
172		p++;
173		*(unsigned short *)p = (l >> 8) & 0xffff;
174		p += 2;
175		while (count--)
176		{
177			l2 = cpu_to_le32(inl(port));
178			*(unsigned int *)p = (l & 0xff) << 24 | (l2 >> 8);
179			p += 4;
180			l = l2;
181		}
182		*p = l & 0xff;
183		break;
184	 case 0x03:			/* Buffer 8-bit aligned */
185		--count;
186
187		l = cpu_to_le32(inl(port));
188		*p = l >> 24;
189		p++;
190		while (count--)
191		{
192			l2 = cpu_to_le32(inl(port));
193			*(unsigned int *)p = (l & 0xffffff) << 8 | l2 >> 24;
194			p += 4;
195			l = l2;
196		}
197		*(unsigned short *)p = (l >> 8) & 0xffff;
198		p += 2;
199		*p = l & 0xff;
200		break;
201	}
202}
203
204
205/*
206 * Like insb but in the opposite direction.
207 * Don't worry as much about doing aligned memory transfers:
208 * doing byte reads the "slow" way isn't nearly as slow as
209 * doing byte writes the slow way (no r-m-w cycle).
210 */
211void outsb(unsigned long port, const void * src, unsigned long count)
212{
213	const unsigned char *p;
214
215	p = (const unsigned char *)src;
216	while (count) {
217		count--;
218		outb(*p, port);
219		p++;
220	}
221}
222
223/*
224 * Like insw but in the opposite direction.  This is used by the IDE
225 * driver to write disk sectors.  Performance is important, but the
226 * interfaces seems to be slow: just using the inlined version of the
227 * outw() breaks things.
228 */
229void outsw (unsigned long port, const void *src, unsigned long count)
230{
231	unsigned int l = 0, l2;
232	const unsigned char *p;
233
234	p = (const unsigned char *)src;
235
236	if (!count)
237		return;
238
239	switch (((unsigned long)p) & 0x3)
240	{
241	 case 0x00:			/* Buffer 32-bit aligned */
242		while (count>=2) {
243			count -= 2;
244			l = *(unsigned int *)p;
245			p += 4;
246			outw(le16_to_cpu(l >> 16), port);
247			outw(le16_to_cpu(l & 0xffff), port);
248		}
249		if (count) {
250			outw(le16_to_cpu(*(unsigned short*)p), port);
251		}
252		break;
253
254	 case 0x02:			/* Buffer 16-bit aligned */
255
256		outw(le16_to_cpu(*(unsigned short*)p), port);
257		p += 2;
258		count--;
259
260		while (count>=2) {
261			count -= 2;
262			l = *(unsigned int *)p;
263			p += 4;
264			outw(le16_to_cpu(l >> 16), port);
265			outw(le16_to_cpu(l & 0xffff), port);
266		}
267		if (count) {
268			outw(le16_to_cpu(*(unsigned short *)p), port);
269		}
270		break;
271
272	 case 0x01:			/* Buffer 8-bit aligned */
273		/* I don't bother with 32bit transfers
274		 * in this case, 16bit will have to do -- DE */
275
276		l  = *p << 8;
277		p++;
278		count--;
279		while (count)
280		{
281			count--;
282			l2 = *(unsigned short *)p;
283			p += 2;
284			outw(le16_to_cpu(l | l2 >> 8), port);
285		        l = l2 << 8;
286		}
287		l2 = *(unsigned char *)p;
288		outw (le16_to_cpu(l | l2>>8), port);
289		break;
290
291	}
292}
293
294
295/*
296 * Like insl but in the opposite direction.  This is used by the IDE
297 * driver to write disk sectors.  Works with any alignment in SRC.
298 *  Performance is important, but the interfaces seems to be slow:
299 * just using the inlined version of the outl() breaks things.
300 */
301void outsl (unsigned long port, const void *src, unsigned long count)
302{
303	unsigned int l = 0, l2;
304	const unsigned char *p;
305
306	p = (const unsigned char *)src;
307
308	if (!count)
309		return;
310
311	switch (((unsigned long)p) & 0x3)
312	{
313	 case 0x00:			/* Buffer 32-bit aligned */
314		while (count--)
315		{
316			outl(le32_to_cpu(*(unsigned int *)p), port);
317			p += 4;
318		}
319		break;
320
321	 case 0x02:			/* Buffer 16-bit aligned */
322		--count;
323
324		l = *(unsigned short *)p;
325		p += 2;
326
327		while (count--)
328		{
329			l2 = *(unsigned int *)p;
330			p += 4;
331			outl (le32_to_cpu(l << 16 | l2 >> 16), port);
332			l = l2;
333		}
334		l2 = *(unsigned short *)p;
335		outl (le32_to_cpu(l << 16 | l2), port);
336		break;
337	 case 0x01:			/* Buffer 8-bit aligned */
338		--count;
339
340		l = *p << 24;
341		p++;
342		l |= *(unsigned short *)p << 8;
343		p += 2;
344
345		while (count--)
346		{
347			l2 = *(unsigned int *)p;
348			p += 4;
349			outl (le32_to_cpu(l | l2 >> 24), port);
350			l = l2 << 8;
351		}
352		l2 = *p;
353		outl (le32_to_cpu(l | l2), port);
354		break;
355	 case 0x03:			/* Buffer 8-bit aligned */
356		--count;
357
358		l = *p << 24;
359		p++;
360
361		while (count--)
362		{
363			l2 = *(unsigned int *)p;
364			p += 4;
365			outl (le32_to_cpu(l | l2 >> 8), port);
366			l = l2 << 24;
367		}
368		l2 = *(unsigned short *)p << 16;
369		p += 2;
370		l2 |= *p;
371		outl (le32_to_cpu(l | l2), port);
372		break;
373	}
374}
375
376EXPORT_SYMBOL(insb);
377EXPORT_SYMBOL(insw);
378EXPORT_SYMBOL(insl);
379EXPORT_SYMBOL(outsb);
380EXPORT_SYMBOL(outsw);
381EXPORT_SYMBOL(outsl);
~/ Read-only file preview.