• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * drivers/bch/bchlib_write.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 <stdbool.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include "bch.h"
31 
32 /****************************************************************************
33  * Public Functions
34  ****************************************************************************/
35 
36 /****************************************************************************
37  * Name: bchlib_write
38  *
39  * Description:
40  *   Write to the block device set-up by bchlib_setup as if it were a character
41  *   device.
42  *
43  ****************************************************************************/
44 
bchlib_write(void * handle,const char * buffer,loff_t offset,size_t len)45 ssize_t bchlib_write(void *handle, const char *buffer, loff_t offset, size_t len)
46 {
47   struct bchlib_s *bch = (struct bchlib_s *)handle;
48   size_t   nsectors;
49   unsigned long long   sector;
50   uint16_t sectoffset;
51   size_t   nbytes;
52   size_t   byteswritten;
53   int      ret;
54 
55   /* Get rid of this special case right away */
56 
57   if (len < 1)
58     {
59       return 0;
60     }
61 
62   /* Convert the file position into a sector number and offset. */
63 
64   sector     = offset / bch->sectsize;
65   sectoffset = offset - sector * bch->sectsize;
66 
67   if (sector >= bch->nsectors)
68     {
69       return 0;
70     }
71 
72   /* Write the initial partial sector */
73 
74   byteswritten = 0;
75   if (sectoffset > 0)
76     {
77       /* Read the full sector into the sector buffer */
78 
79       ret = bchlib_readsector(bch, sector + bch->sectstart);
80       if (ret < 0)
81         {
82           return byteswritten;
83         }
84 
85       /* Copy the tail end of the sector from the user buffer */
86 
87       if (sectoffset + len > bch->sectsize)
88         {
89           nbytes = bch->sectsize - sectoffset;
90         }
91       else
92         {
93           nbytes = len;
94         }
95 
96       ret = LOS_CopyToKernel(&bch->buffer[sectoffset], nbytes, buffer, nbytes);
97       if (ret != EOK)
98         {
99           PRINTK("ERROR: bchlib_write failed: %d\n", ret);
100           return byteswritten;
101         }
102       bch->dirty = true;
103 
104       /* Adjust pointers and counts */
105 
106       sector++;
107 
108       if (sector >= bch->nsectors)
109         {
110           return nbytes;
111         }
112 
113       byteswritten  = nbytes;
114       buffer       += nbytes;
115       len          -= nbytes;
116     }
117 
118   /* Then write all of the full sectors following the partial sector
119    * directly from the user buffer.
120    */
121 
122   if (len >= bch->sectsize)
123     {
124       nsectors = len / bch->sectsize;
125       if (sector + nsectors > bch->nsectors)
126         {
127           nsectors = bch->nsectors - sector;
128         }
129 
130       /* Write the contiguous sectors */
131 
132       ret = los_disk_write(bch->disk->disk_id, (const void *)buffer,
133                            sector + bch->sectstart, nsectors);
134       if (ret < 0)
135         {
136           PRINTK("ERROR: Write failed: %d\n", ret);
137           return byteswritten;
138         }
139 
140       /* Adjust pointers and counts */
141 
142       sector       += nsectors;
143       nbytes        = nsectors * bch->sectsize;
144       byteswritten += nbytes;
145 
146       if (sector >= bch->nsectors)
147         {
148           return byteswritten;
149         }
150 
151       buffer    += nbytes;
152       len       -= nbytes;
153     }
154 
155   /* Then write any partial final sector */
156 
157   if (len > 0)
158     {
159       /* Read the sector into the sector buffer */
160 
161       ret = bchlib_readsector(bch, sector + bch->sectstart);
162       if (ret < 0)
163         {
164           return byteswritten;
165         }
166 
167       /* Copy the head end of the sector from the user buffer */
168 
169       ret = LOS_CopyToKernel(bch->buffer, len, buffer, len);
170       if (ret != EOK)
171         {
172           PRINTK("ERROR: bchlib_write failed: %d\n", ret);
173           return byteswritten;
174         }
175       bch->dirty = true;
176 
177       /* Adjust counts */
178 
179       byteswritten += len;
180     }
181 
182   /* Finally, flush any cached writes to the device as well */
183 
184   ret = bchlib_flushsector(bch);
185   if (ret < 0)
186     {
187       PRINTK("ERROR: Flush failed: %d\n", ret);
188       return byteswritten;
189     }
190 
191   return byteswritten;
192 }
193 
194