1/**************************************************************************** 2 * drivers/bch/bchlib_read.c 3 * 4 * Licensed to the Apache Software Foundation (ASF) under one or more 5 * contributor license agreements. See the NOTICE file distributed with 6 * this work for additional information regarding copyright ownership. The 7 * ASF licenses this file to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance with the 9 * License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16 * License for the specific language governing permissions and limitations 17 * under the License. 18 * 19 ****************************************************************************/ 20 21/**************************************************************************** 22 * Included Files 23 ****************************************************************************/ 24#include <sys/types.h> 25#include <stdint.h> 26#include <string.h> 27#include <errno.h> 28#include <assert.h> 29#include "bch.h" 30#include <stdlib.h> 31 32/**************************************************************************** 33 * Private Types 34 ****************************************************************************/ 35 36/**************************************************************************** 37 * Private Function Prototypes 38 ****************************************************************************/ 39 40/**************************************************************************** 41 * Private Data 42 ****************************************************************************/ 43 44/**************************************************************************** 45 * Private Functions 46 ****************************************************************************/ 47 48/**************************************************************************** 49 * Public Functions 50 ****************************************************************************/ 51 52/**************************************************************************** 53 * Name: bchlib_read 54 * 55 * Description: 56 * Read from the block device set-up by bchlib_setup as if it were a character 57 * device. 58 * 59 ****************************************************************************/ 60 61ssize_t bchlib_read(void *handle, char *buffer, loff_t offset, size_t len) 62{ 63 struct bchlib_s *bch = (struct bchlib_s *)handle; 64 size_t nsectors; 65 unsigned long long sector; 66 uint16_t sectoffset; 67 size_t nbytes; 68 size_t bytesread; 69 int ret; 70 71 /* Get rid of this special case right away */ 72 73 if (len < 1) 74 { 75 return 0; 76 } 77 78 /* Convert the file position into a sector number an offset. */ 79 80 sector = offset / bch->sectsize; 81 sectoffset = offset - sector * bch->sectsize; 82 83 if (sector >= bch->nsectors) 84 { 85 /* Return end-of-file */ 86 87 return 0; 88 } 89 90 /* Read the initial partial sector */ 91 92 bytesread = 0; 93 if (sectoffset > 0) 94 { 95 /* Read the sector into the sector buffer */ 96 97 ret = bchlib_readsector(bch, sector + bch->sectstart); 98 if (ret < 0) 99 { 100 return bytesread; 101 } 102 103 /* Copy the tail end of the sector to the user buffer */ 104 105 if (sectoffset + len > bch->sectsize) 106 { 107 nbytes = bch->sectsize - sectoffset; 108 } 109 else 110 { 111 nbytes = len; 112 } 113 114 ret = LOS_CopyFromKernel(buffer, len, &bch->buffer[sectoffset], nbytes); 115 if (ret != EOK) 116 { 117 PRINTK("ERROR: bchlib_read failed: %d\n", ret); 118 return bytesread; 119 } 120 121 /* Adjust pointers and counts */ 122 123 ++sector; 124 125 if (sector >= bch->nsectors) 126 { 127 return nbytes; 128 } 129 130 bytesread = nbytes; 131 buffer += nbytes; 132 len -= nbytes; 133 } 134 135 /* Then read all of the full sectors following the partial sector directly 136 * into the user buffer. 137 */ 138 139 if (len >= bch->sectsize) 140 { 141 nsectors = len / bch->sectsize; 142 if (sector + nsectors > bch->nsectors) 143 { 144 nsectors = bch->nsectors - sector; 145 } 146 /* No need for reading large contiguous data, useRead(param 4) is set TRUE */ 147 ret = los_disk_read(bch->disk->disk_id, (void *)buffer, sector + bch->sectstart, nsectors, TRUE); 148 149 if (ret < 0) 150 { 151 PRINTK("ERROR: Read failed: %d\n", ret); 152 return bytesread; 153 } 154 155 /* Adjust pointers and counts */ 156 157 sector += nsectors; 158 nbytes = nsectors * bch->sectsize; 159 bytesread += nbytes; 160 161 if (sector >= bch->nsectors) 162 { 163 return bytesread; 164 } 165 166 buffer += nbytes; 167 len -= nbytes; 168 } 169 170 /* Then read any partial final sector */ 171 172 if (len > 0) 173 { 174 /* Read the sector into the sector buffer */ 175 176 ret = bchlib_readsector(bch, sector + bch->sectstart); 177 if (ret < 0) 178 { 179 return bytesread; 180 } 181 182 /* Copy the head end of the sector to the user buffer */ 183 184 ret = LOS_CopyFromKernel(buffer, len, bch->buffer, len); 185 if (ret != EOK) 186 { 187 PRINTK("ERROR: bchlib_read failed: %d\n", ret); 188 return bytesread; 189 } 190 191 /* Adjust counts */ 192 193 bytesread += len; 194 } 195 196 return bytesread; 197} 198