1/****************************************************************************
2 * drivers/bch/bchdev_unregister.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/stat.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <sched.h>
28#include <errno.h>
29#include <assert.h>
30#include <sys/ioctl.h>
31#include "bch.h"
32#include "fs/driver.h"
33
34#define _err PRINTK
35
36/****************************************************************************
37 * Public Functions
38 ****************************************************************************/
39
40/****************************************************************************
41 * Name: bchdev_unregister
42 *
43 * Description:
44 *   Unregister character driver access to a block device that was created
45 *   by a previous call to bchdev_register().
46 *
47 ****************************************************************************/
48
49int bchdev_unregister(const char *chardev)
50{
51  struct bchlib_s *bch;
52  int fd;
53  int ret;
54
55  /* Sanity check */
56
57  if (!chardev)
58    {
59      return -EINVAL;
60    }
61
62  /* Open the character driver associated with chardev */
63
64  fd = open(chardev, O_RDONLY);
65  if (fd < 0)
66    {
67      _err("ERROR: Failed to open %s: %d\n", chardev, errno);
68      return -errno;
69    }
70
71  /* Get a reference to the internal data structure.  On success, we
72   * will hold a reference count on the state structure.
73   */
74
75  ret = ioctl(fd, DIOC_GETPRIV, (unsigned long)((uintptr_t)&bch));
76  (void)close(fd);
77
78  if (ret < 0)
79    {
80      _err("ERROR: ioctl failed: %d\n", errno);
81      return -errno;
82    }
83
84  /* Lock out context switches.  If there are no other references
85   * and no context switches, then we can assume that we can safely
86   * teardown the driver.
87   */
88
89  LOS_TaskLock();
90
91  /* Check if the internal structure is non-busy (we hold one reference). */
92
93  if (bch->refs > 1)
94    {
95      ret = -EBUSY;
96      goto errout_with_lock;
97    }
98
99  /* Unregister the driver (this cannot suspend or we lose our non-preemptive
100   * state!).  Once the driver is successfully unregistered, we can assume
101   * we have exclusive access to the state instance.
102   */
103
104  ret = unregister_driver(chardev);
105  if (ret < 0)
106    {
107      goto errout_with_lock;
108    }
109
110  LOS_TaskUnlock();
111
112  /* Release the internal structure */
113
114  bch->refs = 0;
115  return bchlib_teardown(bch);
116
117errout_with_lock:
118  bch->refs--;
119  LOS_TaskUnlock();
120  return ret;
121}
122