• 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       /* Flush the dirty sector to keep the sector sequence */
131 
132       ret = bchlib_flushsector(bch);
133       if (ret < 0)
134         {
135           PRINTK("ERROR: Flush failed: %d\n", ret);
136           return ret;
137         }
138 
139       /* Write the contiguous sectors */
140 
141       ret = los_disk_write(bch->disk->disk_id, (const void *)buffer,
142                            sector + bch->sectstart, nsectors);
143       if (ret < 0)
144         {
145           PRINTK("ERROR: Write failed: %d\n", ret);
146           return byteswritten;
147         }
148 
149       /* Adjust pointers and counts */
150 
151       sector       += nsectors;
152       nbytes        = nsectors * bch->sectsize;
153       byteswritten += nbytes;
154 
155       if (sector >= bch->nsectors)
156         {
157           return byteswritten;
158         }
159 
160       buffer    += nbytes;
161       len       -= nbytes;
162     }
163 
164   /* Then write any partial final sector */
165 
166   if (len > 0)
167     {
168       /* Read the sector into the sector buffer */
169 
170       ret = bchlib_readsector(bch, sector + bch->sectstart);
171       if (ret < 0)
172         {
173           return byteswritten;
174         }
175 
176       /* Copy the head end of the sector from the user buffer */
177 
178       ret = LOS_CopyToKernel(bch->buffer, len, buffer, len);
179       if (ret != EOK)
180         {
181           PRINTK("ERROR: bchlib_write failed: %d\n", ret);
182           return byteswritten;
183         }
184       bch->dirty = true;
185 
186       /* Adjust counts */
187 
188       byteswritten += len;
189     }
190 
191   return byteswritten;
192 }
193 
194