1/*
2 * Copyright 2005, J��r��me DUVAL. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <Drivers.h>
7#include <OS.h>
8#include <bus_manager.h>
9#include <malloc.h>
10#include <module.h>
11#include <stdio.h>
12#include <string.h>
13#include <sys/ioccom.h>
14#include <sys/ioctl.h>
15
16#define __KERNEL__
17#include <pcmcia/cs_types.h>
18#include <pcmcia/cs.h>
19#include <pcmcia/cistpl.h>
20#include <pcmcia/ds.h>
21
22#define copy_from_user memcpy
23#define copy_to_user memcpy
24#define CardServices gPcmciaCs->_CardServices
25#define get_handle gPcmciaDs->get_handle
26
27const char sockname[] = "bus/pcmcia/sock/%ld";
28static char ** devices;
29uint32 devices_count = 0;
30
31int32 api_version = B_CUR_DRIVER_API_VERSION;
32
33cs_client_module_info *gPcmciaCs;
34ds_module_info *gPcmciaDs;
35
36static status_t
37ds_open(const char *name, uint32 flags, void **_cookie)
38{
39	int32 socket = -1;
40	int32 i;
41	*_cookie = NULL;
42
43	for (i=0; i<devices_count; i++) {
44		if (strcmp(name, devices[i]) == 0) {
45			socket = i;
46			break;
47		}
48	}
49
50	if (socket < 0) {
51		return B_BAD_VALUE;
52	}
53
54	if (get_handle(socket, (client_handle_t *)_cookie) != B_OK) {
55		return ENODEV;
56	}
57
58	return B_OK;
59}
60
61
62static status_t
63ds_close(void *cookie)
64{
65	return B_OK;
66}
67
68
69static status_t
70ds_free(void *cookie)
71{
72	return B_OK;
73}
74
75
76static status_t
77ds_read(void *cookie, off_t position, void *data, size_t *numBytes)
78{
79	return B_ERROR;
80}
81
82
83static status_t
84ds_write(void *cookie, off_t position, const void *data, size_t *numBytes)
85{
86	return B_ERROR;
87}
88
89
90/*====================================================================*/
91
92static status_t
93ds_ioctl(void *cookie, uint32 cmd, void *arg, size_t len)
94{
95	/*socket_info_t *s = (socket_info_t *) cookie;
96    u_int size = IOCPARM_LEN(cmd);
97    status_t ret, err;
98    ds_ioctl_arg_t buf;
99
100    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
101
102	err = ret = 0;
103
104    if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
105
106    switch (cmd) {
107    case DS_ADJUST_RESOURCE_INFO:
108	ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust);
109	break;
110    case DS_GET_CARD_SERVICES_INFO:
111	ret = CardServices(GetCardServicesInfo, &buf.servinfo);
112	break;
113    case DS_GET_CONFIGURATION_INFO:
114	ret = CardServices(GetConfigurationInfo, s->handle, &buf.config);
115	break;
116    case DS_GET_FIRST_TUPLE:
117	ret = CardServices(GetFirstTuple, s->handle, &buf.tuple);
118	break;
119    case DS_GET_NEXT_TUPLE:
120	ret = CardServices(GetNextTuple, s->handle, &buf.tuple);
121	break;
122    case DS_GET_TUPLE_DATA:
123	buf.tuple.TupleData = buf.tuple_parse.data;
124	buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
125	ret = CardServices(GetTupleData, s->handle, &buf.tuple);
126	break;
127    case DS_PARSE_TUPLE:
128	buf.tuple.TupleData = buf.tuple_parse.data;
129	ret = CardServices(ParseTuple, s->handle, &buf.tuple,
130			   &buf.tuple_parse.parse);
131	break;
132    case DS_RESET_CARD:
133	ret = CardServices(ResetCard, s->handle, NULL);
134	break;
135    case DS_GET_STATUS:
136	ret = CardServices(GetStatus, s->handle, &buf.status);
137	break;
138    case DS_VALIDATE_CIS:
139	ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo);
140	break;
141    case DS_SUSPEND_CARD:
142	ret = CardServices(SuspendCard, s->handle, NULL);
143	break;
144    case DS_RESUME_CARD:
145	ret = CardServices(ResumeCard, s->handle, NULL);
146	break;
147    case DS_EJECT_CARD:
148	ret = CardServices(EjectCard, s->handle, NULL);
149	break;
150    case DS_INSERT_CARD:
151	ret = CardServices(InsertCard, s->handle, NULL);
152	break;
153    case DS_ACCESS_CONFIGURATION_REGISTER:
154	if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN))
155	    return -EPERM;
156	ret = CardServices(AccessConfigurationRegister, s->handle,
157			   &buf.conf_reg);
158	break;
159    case DS_GET_FIRST_REGION:
160        ret = CardServices(GetFirstRegion, s->handle, &buf.region);
161	break;
162    case DS_GET_NEXT_REGION:
163	ret = CardServices(GetNextRegion, s->handle, &buf.region);
164	break;
165    case DS_GET_FIRST_WINDOW:
166	buf.win_info.handle = (window_handle_t)s->handle;
167	ret = CardServices(GetFirstWindow, &buf.win_info.handle,
168			   &buf.win_info.window);
169	break;
170    case DS_GET_NEXT_WINDOW:
171	ret = CardServices(GetNextWindow, &buf.win_info.handle,
172			   &buf.win_info.window);
173	break;
174    case DS_GET_MEM_PAGE:
175	ret = CardServices(GetMemPage, buf.win_info.handle,
176			   &buf.win_info.map);
177	break;
178    case DS_REPLACE_CIS:
179	ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump);
180	break;
181	*/
182	client_handle_t h = (client_handle_t) cookie;
183    u_int size = IOCPARM_LEN(cmd);
184    status_t ret, err;
185    ds_ioctl_arg_t buf;
186
187    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
188
189	err = ret = 0;
190
191    if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
192
193    switch (cmd) {
194    case DS_ADJUST_RESOURCE_INFO:
195	ret = CardServices(AdjustResourceInfo, h, &buf.adjust);
196	break;
197    case DS_GET_CARD_SERVICES_INFO:
198	ret = CardServices(GetCardServicesInfo, &buf.servinfo);
199	break;
200    case DS_GET_CONFIGURATION_INFO:
201	ret = CardServices(GetConfigurationInfo, h, &buf.config);
202	break;
203    case DS_GET_FIRST_TUPLE:
204	ret = CardServices(GetFirstTuple, h, &buf.tuple);
205	break;
206    case DS_GET_NEXT_TUPLE:
207	ret = CardServices(GetNextTuple, h, &buf.tuple);
208	break;
209    case DS_GET_TUPLE_DATA:
210	buf.tuple.TupleData = buf.tuple_parse.data;
211	buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
212	ret = CardServices(GetTupleData, h, &buf.tuple);
213	break;
214    case DS_PARSE_TUPLE:
215	buf.tuple.TupleData = buf.tuple_parse.data;
216	ret = CardServices(ParseTuple, h, &buf.tuple,
217			   &buf.tuple_parse.parse);
218	break;
219    case DS_RESET_CARD:
220	ret = CardServices(ResetCard, h, NULL);
221	break;
222    case DS_GET_STATUS:
223	ret = CardServices(GetStatus, h, &buf.status);
224	break;
225    case DS_VALIDATE_CIS:
226	ret = CardServices(ValidateCIS, h, &buf.cisinfo);
227	break;
228    case DS_SUSPEND_CARD:
229	ret = CardServices(SuspendCard, h, NULL);
230	break;
231    case DS_RESUME_CARD:
232	ret = CardServices(ResumeCard, h, NULL);
233	break;
234    case DS_EJECT_CARD:
235	ret = CardServices(EjectCard, h, NULL);
236	break;
237    case DS_INSERT_CARD:
238	ret = CardServices(InsertCard, h, NULL);
239	break;
240/*    case DS_ACCESS_CONFIGURATION_REGISTER:
241	if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN))
242	    return -EPERM;
243	ret = CardServices(AccessConfigurationRegister, h,
244			   &buf.conf_reg);
245	break;
246    case DS_GET_FIRST_REGION:
247        ret = CardServices(GetFirstRegion, h, &buf.region);
248	break;
249    case DS_GET_NEXT_REGION:
250	ret = CardServices(GetNextRegion, h, &buf.region);
251	break;
252    case DS_GET_FIRST_WINDOW:
253	buf.win_info.handle = (window_handle_t)h;
254	ret = CardServices(GetFirstWindow, &buf.win_info.handle,
255			   &buf.win_info.window);
256	break;
257    case DS_GET_NEXT_WINDOW:
258	ret = CardServices(GetNextWindow, &buf.win_info.handle,
259			   &buf.win_info.window);
260	break;
261    case DS_GET_MEM_PAGE:
262	ret = CardServices(GetMemPage, buf.win_info.handle,
263			   &buf.win_info.map);
264	break;*/
265    case DS_REPLACE_CIS:
266	ret = CardServices(ReplaceCIS, h, &buf.cisdump);
267	break;
268
269/*    case DS_BIND_REQUEST:
270	if (!capable(CAP_SYS_ADMIN)) return -EPERM;
271	err = bind_request(i, &buf.bind_info);
272	break;
273    case DS_GET_DEVICE_INFO:
274	err = get_device_info(i, &buf.bind_info, 1);
275	break;
276    case DS_GET_NEXT_DEVICE:
277	err = get_device_info(i, &buf.bind_info, 0);
278	break;
279    case DS_UNBIND_REQUEST:
280	err = unbind_request(i, &buf.bind_info);
281	break;
282    case DS_BIND_MTD:
283	if (!capable(CAP_SYS_ADMIN)) return -EPERM;
284	err = bind_mtd(i, &buf.mtd_info);
285	break;*/
286    default:
287    err = -EINVAL;
288    }
289
290    if ((err == 0) && (ret != CS_SUCCESS)) {
291	switch (ret) {
292	case CS_BAD_SOCKET: case CS_NO_CARD:
293	    err = ENODEV; break;
294	case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
295	case CS_BAD_TUPLE:
296		err = EINVAL; break;
297	case CS_IN_USE:
298	    err = EBUSY; break;
299	case CS_OUT_OF_RESOURCE:
300	    err = ENOSPC; break;
301	case CS_NO_MORE_ITEMS:
302	    err = ENODATA; break;
303	case CS_UNSUPPORTED_FUNCTION:
304	    err = ENOSYS; break;
305	default:
306	    err = EIO; break;
307	}
308    }
309
310    if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size);
311
312    return err;
313} /* ds_ioctl */
314
315
316status_t
317init_hardware()
318{
319	return B_OK;
320}
321
322
323const char **
324publish_devices(void)
325{
326	return (const char **)devices;
327}
328
329
330static device_hooks hooks = {
331	&ds_open,
332	&ds_close,
333	&ds_free,
334	&ds_ioctl,
335	&ds_read,
336	&ds_write,
337	NULL,
338	NULL,
339	NULL,
340	NULL
341};
342
343device_hooks *
344find_device(const char *name)
345{
346	return &hooks;
347}
348
349
350status_t
351init_driver()
352{
353	status_t err;
354	client_handle_t handle;
355	uint32 i;
356
357#if DEBUG && !defined(__HAIKU__)
358	load_driver_symbols("ds");
359#endif
360
361	if ((err = get_module(CS_CLIENT_MODULE_NAME, (module_info **)&gPcmciaCs))!=B_OK)
362		return err;
363	if ((err = get_module(DS_MODULE_NAME, (module_info **)&gPcmciaDs))!=B_OK) {
364		put_module(CS_CLIENT_MODULE_NAME);
365		return err;
366	}
367
368	devices_count = 0;
369	while (get_handle(devices_count, &handle)==B_OK) {
370		devices_count++;
371	}
372
373	if (devices_count <= 0) {
374		put_module(CS_CLIENT_MODULE_NAME);
375		put_module(DS_MODULE_NAME);
376		return ENODEV;
377	}
378
379	devices = malloc(sizeof(char *) * (devices_count+1));
380	if (!devices) {
381		put_module(CS_CLIENT_MODULE_NAME);
382		put_module(DS_MODULE_NAME);
383		return ENOMEM;
384	}
385	for (i=0; i<devices_count; i++) {
386		devices[i] = strdup(sockname);
387		sprintf(devices[i], sockname, i);
388	}
389	devices[devices_count] = NULL;
390
391	return B_OK;
392}
393
394
395void
396uninit_driver()
397{
398	int32 i = 0;
399	for (i=0; i<devices_count; i++) {
400		free (devices[i]);
401	}
402	free(devices);
403	devices = NULL;
404
405	put_module(DS_MODULE_NAME);
406	put_module(CS_CLIENT_MODULE_NAME);
407}
408
409