PageRenderTime 26ms CodeModel.GetById 20ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/misc/cb710/sgbuf2.c

https://bitbucket.org/ndreys/linux-sunxi
C | 146 lines | 88 code | 19 blank | 39 comment | 14 complexity | 9b2bcc9fdfb14b6bb1c32853cb71fee5 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/*
  2 *  cb710/sgbuf2.c
  3 *
  4 *  Copyright by Micha?‚ Miros?‚aw, 2008-2009
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License version 2 as
  8 * published by the Free Software Foundation.
  9 */
 10#include <linux/kernel.h>
 11#include <linux/module.h>
 12#include <linux/cb710.h>
 13
 14static bool sg_dwiter_next(struct sg_mapping_iter *miter)
 15{
 16	if (sg_miter_next(miter)) {
 17		miter->consumed = 0;
 18		return true;
 19	} else
 20		return false;
 21}
 22
 23static bool sg_dwiter_is_at_end(struct sg_mapping_iter *miter)
 24{
 25	return miter->length == miter->consumed && !sg_dwiter_next(miter);
 26}
 27
 28static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter)
 29{
 30	size_t len, left = 4;
 31	uint32_t data;
 32	void *addr = &data;
 33
 34	do {
 35		len = min(miter->length - miter->consumed, left);
 36		memcpy(addr, miter->addr + miter->consumed, len);
 37		miter->consumed += len;
 38		left -= len;
 39		if (!left)
 40			return data;
 41		addr += len;
 42	} while (sg_dwiter_next(miter));
 43
 44	memset(addr, 0, left);
 45	return data;
 46}
 47
 48static inline bool needs_unaligned_copy(const void *ptr)
 49{
 50#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
 51	return false;
 52#else
 53	return ((ptr - NULL) & 3) != 0;
 54#endif
 55}
 56
 57static bool sg_dwiter_get_next_block(struct sg_mapping_iter *miter, uint32_t **ptr)
 58{
 59	size_t len;
 60
 61	if (sg_dwiter_is_at_end(miter))
 62		return true;
 63
 64	len = miter->length - miter->consumed;
 65
 66	if (likely(len >= 4 && !needs_unaligned_copy(
 67			miter->addr + miter->consumed))) {
 68		*ptr = miter->addr + miter->consumed;
 69		miter->consumed += 4;
 70		return true;
 71	}
 72
 73	return false;
 74}
 75
 76/**
 77 * cb710_sg_dwiter_read_next_block() - get next 32-bit word from sg buffer
 78 * @miter: sg mapping iterator used for reading
 79 *
 80 * Description:
 81 *   Returns 32-bit word starting at byte pointed to by @miter@
 82 *   handling any alignment issues.  Bytes past the buffer's end
 83 *   are not accessed (read) but are returned as zeroes.  @miter@
 84 *   is advanced by 4 bytes or to the end of buffer whichever is
 85 *   closer.
 86 *
 87 * Context:
 88 *   Same requirements as in sg_miter_next().
 89 *
 90 * Returns:
 91 *   32-bit word just read.
 92 */
 93uint32_t cb710_sg_dwiter_read_next_block(struct sg_mapping_iter *miter)
 94{
 95	uint32_t *ptr = NULL;
 96
 97	if (likely(sg_dwiter_get_next_block(miter, &ptr)))
 98		return ptr ? *ptr : 0;
 99
100	return sg_dwiter_read_buffer(miter);
101}
102EXPORT_SYMBOL_GPL(cb710_sg_dwiter_read_next_block);
103
104static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data)
105{
106	size_t len, left = 4;
107	void *addr = &data;
108
109	do {
110		len = min(miter->length - miter->consumed, left);
111		memcpy(miter->addr, addr, len);
112		miter->consumed += len;
113		left -= len;
114		if (!left)
115			return;
116		addr += len;
117	} while (sg_dwiter_next(miter));
118}
119
120/**
121 * cb710_sg_dwiter_write_next_block() - write next 32-bit word to sg buffer
122 * @miter: sg mapping iterator used for writing
123 *
124 * Description:
125 *   Writes 32-bit word starting at byte pointed to by @miter@
126 *   handling any alignment issues.  Bytes which would be written
127 *   past the buffer's end are silently discarded. @miter@ is
128 *   advanced by 4 bytes or to the end of buffer whichever is closer.
129 *
130 * Context:
131 *   Same requirements as in sg_miter_next().
132 */
133void cb710_sg_dwiter_write_next_block(struct sg_mapping_iter *miter, uint32_t data)
134{
135	uint32_t *ptr = NULL;
136
137	if (likely(sg_dwiter_get_next_block(miter, &ptr))) {
138		if (ptr)
139			*ptr = data;
140		else
141			return;
142	} else
143		sg_dwiter_write_slow(miter, data);
144}
145EXPORT_SYMBOL_GPL(cb710_sg_dwiter_write_next_block);
146