1 | /* |
---|
2 | * CAN_MUX driver. Present in GR712RC. |
---|
3 | * |
---|
4 | * COPYRIGHT (c) 2008. |
---|
5 | * Cobham Gaisler AB. |
---|
6 | * |
---|
7 | * The license and distribution terms for this file may be |
---|
8 | * found in the file LICENSE in this distribution or at |
---|
9 | * http://www.rtems.org/license/LICENSE. |
---|
10 | */ |
---|
11 | |
---|
12 | #include <rtems/libio.h> |
---|
13 | #include <stdlib.h> |
---|
14 | #include <stdio.h> |
---|
15 | #include <string.h> |
---|
16 | #include <bsp.h> |
---|
17 | #include <rtems/bspIo.h> /* printk */ |
---|
18 | |
---|
19 | #include <bsp/canmux.h> |
---|
20 | #include <ambapp.h> |
---|
21 | |
---|
22 | #include <grlib_impl.h> |
---|
23 | |
---|
24 | #ifndef GAISLER_CANMUX |
---|
25 | #define GAISLER_CANMUX 0x081 |
---|
26 | #endif |
---|
27 | |
---|
28 | #if !defined(CANMUX_DEVNAME) |
---|
29 | #undef CANMUX_DEVNAME |
---|
30 | #define CANMUX_DEVNAME "/dev/canmux" |
---|
31 | #endif |
---|
32 | |
---|
33 | /* Enable debug output? */ |
---|
34 | /* #define DEBUG */ |
---|
35 | |
---|
36 | #ifdef DEBUG |
---|
37 | #define DBG(x...) printk(x) |
---|
38 | #else |
---|
39 | #define DBG(x...) |
---|
40 | #endif |
---|
41 | |
---|
42 | #define BUSA_SELECT (1 << 0) |
---|
43 | #define BUSB_SELECT (1 << 1) |
---|
44 | |
---|
45 | struct canmux_priv { |
---|
46 | volatile unsigned int *muxreg; |
---|
47 | rtems_id devsem; |
---|
48 | int open; |
---|
49 | }; |
---|
50 | |
---|
51 | static struct canmux_priv *priv; |
---|
52 | |
---|
53 | static rtems_device_driver canmux_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
54 | static rtems_device_driver canmux_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
55 | static rtems_device_driver canmux_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
56 | static rtems_device_driver canmux_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
57 | static rtems_device_driver canmux_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
58 | static rtems_device_driver canmux_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg); |
---|
59 | |
---|
60 | |
---|
61 | static rtems_device_driver canmux_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
62 | { |
---|
63 | rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t*)arg; |
---|
64 | |
---|
65 | DBG("CAN_MUX: IOCTL %d\n\r", ioarg->command); |
---|
66 | |
---|
67 | ioarg->ioctl_return = 0; |
---|
68 | switch(ioarg->command) { |
---|
69 | case CANMUX_IOC_BUSA_SATCAN: *priv->muxreg &= ~BUSA_SELECT; break; |
---|
70 | case CANMUX_IOC_BUSA_OCCAN1: *priv->muxreg |= BUSA_SELECT; break; |
---|
71 | case CANMUX_IOC_BUSB_SATCAN: *priv->muxreg &= ~BUSB_SELECT; break; |
---|
72 | case CANMUX_IOC_BUSB_OCCAN2: *priv->muxreg |= BUSB_SELECT; break; |
---|
73 | default: return RTEMS_NOT_DEFINED; |
---|
74 | } |
---|
75 | |
---|
76 | return RTEMS_SUCCESSFUL; |
---|
77 | } |
---|
78 | |
---|
79 | static rtems_device_driver canmux_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
80 | { |
---|
81 | rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t*)arg; |
---|
82 | |
---|
83 | rw_args->bytes_moved = 0; |
---|
84 | |
---|
85 | return RTEMS_SUCCESSFUL; |
---|
86 | } |
---|
87 | |
---|
88 | static rtems_device_driver canmux_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
89 | { |
---|
90 | rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t*)arg; |
---|
91 | |
---|
92 | rw_args->bytes_moved = 0; |
---|
93 | |
---|
94 | return RTEMS_SUCCESSFUL; |
---|
95 | } |
---|
96 | |
---|
97 | |
---|
98 | static rtems_device_driver canmux_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
99 | { |
---|
100 | DBG("CAN_MUX: Closing %d\n\r",minor); |
---|
101 | |
---|
102 | priv->open = 0; |
---|
103 | return RTEMS_SUCCESSFUL; |
---|
104 | } |
---|
105 | |
---|
106 | |
---|
107 | static rtems_device_driver canmux_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
108 | { |
---|
109 | DBG("CAN_MUX: Opening %d\n\r",minor); |
---|
110 | |
---|
111 | rtems_semaphore_obtain(priv->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT); |
---|
112 | if (priv->open) { |
---|
113 | rtems_semaphore_release(priv->devsem); |
---|
114 | return RTEMS_RESOURCE_IN_USE; /* EBUSY */ |
---|
115 | } |
---|
116 | priv->open = 1; |
---|
117 | rtems_semaphore_release(priv->devsem); |
---|
118 | |
---|
119 | DBG("CAN_MUX: Opening %d success\n\r",minor); |
---|
120 | |
---|
121 | return RTEMS_SUCCESSFUL; |
---|
122 | } |
---|
123 | |
---|
124 | static rtems_device_driver canmux_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
125 | { |
---|
126 | struct ambapp_apb_info d; |
---|
127 | char fs_name[20]; |
---|
128 | rtems_status_code status; |
---|
129 | |
---|
130 | DBG("CAN_MUX: Initialize..\n\r"); |
---|
131 | |
---|
132 | strcpy(fs_name, CANMUX_DEVNAME); |
---|
133 | |
---|
134 | /* Find core and initialize register pointer */ |
---|
135 | if (!ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_CANMUX, &d)) { |
---|
136 | printk("CAN_MUX: Failed to find CAN_MUX core\n\r"); |
---|
137 | return -1; |
---|
138 | } |
---|
139 | |
---|
140 | status = rtems_io_register_name(fs_name, major, minor); |
---|
141 | if (RTEMS_SUCCESSFUL != status) |
---|
142 | rtems_fatal_error_occurred(status); |
---|
143 | |
---|
144 | /* Create private structure */ |
---|
145 | if ((priv = grlib_malloc(sizeof(*priv))) == NULL) { |
---|
146 | printk("CAN_MUX driver could not allocate memory for priv structure\n\r"); |
---|
147 | return -1; |
---|
148 | } |
---|
149 | |
---|
150 | priv->muxreg = (unsigned int*)d.start; |
---|
151 | |
---|
152 | status = rtems_semaphore_create( |
---|
153 | rtems_build_name('M', 'd', 'v', '0'), |
---|
154 | 1, |
---|
155 | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \ |
---|
156 | RTEMS_NO_PRIORITY_CEILING, |
---|
157 | 0, |
---|
158 | &priv->devsem); |
---|
159 | if (status != RTEMS_SUCCESSFUL) { |
---|
160 | printk("CAN_MUX: Failed to create dev semaphore (%d)\n\r", status); |
---|
161 | free(priv); |
---|
162 | return RTEMS_UNSATISFIED; |
---|
163 | } |
---|
164 | |
---|
165 | priv->open = 0; |
---|
166 | |
---|
167 | return RTEMS_SUCCESSFUL; |
---|
168 | } |
---|
169 | |
---|
170 | |
---|
171 | #define CANMUX_DRIVER_TABLE_ENTRY { canmux_initialize, canmux_open, canmux_close, canmux_read, canmux_write, canmux_ioctl } |
---|
172 | |
---|
173 | static rtems_driver_address_table canmux_driver = CANMUX_DRIVER_TABLE_ENTRY; |
---|
174 | |
---|
175 | int canmux_register(void) |
---|
176 | { |
---|
177 | rtems_status_code r; |
---|
178 | rtems_device_major_number m; |
---|
179 | |
---|
180 | DBG("CAN_MUX: canmux_register called\n\r"); |
---|
181 | |
---|
182 | if ((r = rtems_io_register_driver(0, &canmux_driver, &m)) == RTEMS_SUCCESSFUL) { |
---|
183 | DBG("CAN_MUX driver successfully registered, major: %d\n\r", m); |
---|
184 | } else { |
---|
185 | switch(r) { |
---|
186 | case RTEMS_TOO_MANY: |
---|
187 | printk("CAN_MUX rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break; |
---|
188 | case RTEMS_INVALID_NUMBER: |
---|
189 | printk("CAN_MUX rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break; |
---|
190 | case RTEMS_RESOURCE_IN_USE: |
---|
191 | printk("CAN_MUX rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break; |
---|
192 | default: |
---|
193 | printk("CAN_MUX rtems_io_register_driver failed\n\r"); |
---|
194 | } |
---|
195 | return 1; |
---|
196 | } |
---|
197 | |
---|
198 | return 0; |
---|
199 | } |
---|