[Patch] Extended PCMCIA Support

Dan Williams dcbw at redhat.com
Fri Oct 22 20:59:03 PDT 2004


Hi,

In the absence of kernel support for PCMCIA in sysfs, this patch will 
allow PCMCIA network cards to be used just as well as CardBus cards.

1) Coldplug support, PCMCIA cards recognized on startup
2) Sets info.vendor and info.product to something useful
3) Re-parents devices under their correct PCMCIA slots
4) Also makes hotplugging PCMCIA cards work better, gives
     them pretty names and all
5) Only enabled when --enable-pcmcia-support is passed to
     configure
6) Very compartmentalized, minimal changes to actual HAL code

It only supports network devices now (since those devices show up in sysfs 
under /sys/class/net/*).  Serial devices would also work with a bit of 
extra code (grab the device node #s from the pcmcia stab file and match 
those to the /sys/class/net/ttySx/dev file).  Other devices would probably 
require more code.

--------- Patch comments
The patch includes bits of pcmcia_cs code, including a lot of nasty header 
code that's twice as many lines as actual operative code.  But hey, 
whatever.  pcmcia_cs code is either MPL or GPLv2, and since HAL is GPLv2, 
there is no problem appropriating the code into HAL as long as David Hinds 
is given credit (which he is).
------------------------

Cheers,
Dan
-------------- next part --------------
--- hal-0.4.0/hald/linux/pcmcia_cs.h.pcmcia-support	2004-10-22 22:06:52.576601246 -0400
+++ hal-0.4.0/hald/linux/pcmcia_cs.h	2004-10-22 22:06:52.575601306 -0400
@@ -0,0 +1,515 @@
+/***************************************************************************
+ * CVSID: $Id: pcmcia_utils.h,v 1.19 2004/10/14 18:41:27 david Exp $
+ *
+ * PCMCIA Card utilities
+ *
+ * Copyright (C) 2003 Dan Williams <dcbw at redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ *
+ * Most of this code was derived from pcmcia-cs code, originally
+ * developed by David A. Hinds <dahinds at users.sourceforge.net>.
+ * Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds.
+ * All Rights Reserved.  It has been modified for integration into HAL
+ * by Dan Williams and is covered by the GPL version 2 license.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ **************************************************************************/
+
+#ifndef PCMCIA_CS_H
+#define PCMCIA_CS_H
+
+#include <sys/types.h>
+
+/* cs_types.h */
+typedef u_short	ioaddr_t;
+typedef u_short	socket_t;
+typedef u_int	event_t;
+typedef u_char	cisdata_t;
+typedef u_short	page_t;
+
+struct client_t;
+typedef struct client_t *client_handle_t;
+
+struct window_t;
+typedef struct window_t *window_handle_t;
+
+struct region_t;
+typedef struct region_t *memory_handle_t;
+
+struct eraseq_t;
+typedef struct eraseq_t *eraseq_handle_t;
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+typedef char dev_info_t[DEV_NAME_LEN];
+
+/* cs.h */
+
+/* For AccessConfigurationRegister */
+typedef struct conf_reg_t {
+    u_char	Function;
+    u_int	Action;
+    off_t	Offset;
+    u_int	Value;
+} conf_reg_t;
+
+/* Actions */
+#define CS_READ		1
+#define CS_WRITE	2
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+    u_int	Action;
+    u_int	Resource;
+    u_int	Attributes;
+    union {
+	struct memory {
+	    u_long	Base;
+	    u_long	Size;
+	} memory;
+	struct io {
+	    ioaddr_t	BasePort;
+	    ioaddr_t	NumPorts;
+	    u_int	IOAddrLines;
+	} io;
+	struct irq {
+	    u_int	IRQ;
+	} irq;
+    } resource;
+} adjust_t;
+
+typedef struct servinfo_t {
+    char	Signature[2];
+    u_int	Count;
+    u_int	Revision;
+    u_int	CSLevel;
+    char	*VendorString;
+} servinfo_t;
+
+typedef struct event_callback_args_t {
+    client_handle_t client_handle;
+    void	*info;
+    void	*mtdrequest;
+    void	*buffer;
+    void	*misc;
+    void	*client_data;
+    struct bus_operations *bus;
+} event_callback_args_t;
+
+/* for GetConfigurationInfo */
+typedef struct config_info_t {
+    u_char	Function;
+    u_int	Attributes;
+    u_int	Vcc, Vpp1, Vpp2;
+    u_int	IntType;
+    u_int	ConfigBase;
+    u_char	Status, Pin, Copy, Option, ExtStatus;
+    u_int	Present;
+    u_int	CardValues;
+    u_int	AssignedIRQ;
+    u_int	IRQAttributes;
+    ioaddr_t	BasePort1;
+    ioaddr_t	NumPorts1;
+    u_int	Attributes1;
+    ioaddr_t	BasePort2;
+    ioaddr_t	NumPorts2;
+    u_int	Attributes2;
+    u_int	IOAddrLines;
+} config_info_t;
+
+/* For GetFirst/NextClient */
+typedef struct client_req_t {
+    socket_t	Socket;
+    u_int	Attributes;
+} client_req_t;
+
+#define CLIENT_THIS_SOCKET	0x01
+
+/* For RegisterClient */
+typedef struct client_reg_t {
+    dev_info_t	*dev_info;
+    u_int	Attributes;
+    u_int	EventMask;
+    int		(*event_handler)(event_t event, int priority,
+				 event_callback_args_t *);
+    event_callback_args_t event_callback_args;
+    u_int	Version;
+} client_reg_t;
+
+/* IntType field */
+#define INT_CARDBUS		0x04
+
+/* For GetMemPage, MapMemPage */
+typedef struct memreq_t {
+    u_int	CardOffset;
+    page_t	Page;
+} memreq_t;
+
+/* For ModifyWindow */
+typedef struct modwin_t {
+    u_int	Attributes;
+    u_int	AccessSpeed;
+} modwin_t;
+
+/* For RequestWindow */
+typedef struct win_req_t {
+    u_int	Attributes;
+    u_long	Base;
+    u_int	Size;
+    u_int	AccessSpeed;
+} win_req_t;
+
+typedef struct cs_status_t {
+    u_char	Function;
+    event_t 	CardState;
+    event_t	SocketState;
+} cs_status_t;
+
+typedef struct error_info_t {
+    int		func;
+    int		retcode;
+} error_info_t;
+
+/* Special stuff for binding drivers to sockets */
+typedef struct bind_req_t {
+    socket_t	Socket;
+    u_char	Function;
+    dev_info_t	*dev_info;
+} bind_req_t;
+
+/* Flag to bind to all functions */
+#define BIND_FN_ALL	0xff
+
+typedef struct mtd_bind_t {
+    socket_t	Socket;
+    u_int	Attributes;
+    u_int	CardOffset;
+    dev_info_t	*dev_info;
+} mtd_bind_t;
+
+
+/* cistpl.h */
+
+#define CISTPL_VERS_1		0x15
+#define CISTPL_MANFID		0x20
+#define CISTPL_FUNCID		0x21
+
+typedef struct cistpl_longlink_t {
+    u_int	addr;
+} cistpl_longlink_t;
+
+typedef struct cistpl_checksum_t {
+    u_short	addr;
+    u_short	len;
+    u_char	sum;
+} cistpl_checksum_t;
+
+#define CISTPL_MAX_FUNCTIONS	8
+
+typedef struct cistpl_longlink_mfc_t {
+    u_char	nfn;
+    struct {
+	u_char	space;
+	u_int	addr;
+    } fn[CISTPL_MAX_FUNCTIONS];
+} cistpl_longlink_mfc_t;
+
+#define CISTPL_MAX_ALTSTR_STRINGS	4
+
+typedef struct cistpl_altstr_t {
+    u_char	ns;
+    u_char	ofs[CISTPL_MAX_ALTSTR_STRINGS];
+    char	str[254];
+} cistpl_altstr_t;
+
+#define CISTPL_MAX_DEVICES	4
+
+typedef struct cistpl_device_t {
+    u_char	ndev;
+    struct {
+	u_char 	type;
+	u_char	wp;
+	u_int	speed;
+	u_int	size;
+    } dev[CISTPL_MAX_DEVICES];
+} cistpl_device_t;
+
+typedef struct cistpl_device_o_t {
+    u_char		flags;
+    cistpl_device_t	device;
+} cistpl_device_o_t;
+
+#define CISTPL_VERS_1_MAX_PROD_STRINGS	4
+
+typedef struct cistpl_vers_1_t {
+    u_char	major;
+    u_char	minor;
+    u_char	ns;
+    u_char	ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
+    char	str[254];
+} cistpl_vers_1_t;
+
+typedef struct cistpl_jedec_t {
+    u_char	nid;
+    struct {
+	u_char	mfr;
+	u_char	info;
+    } id[CISTPL_MAX_DEVICES];
+} cistpl_jedec_t;
+
+typedef struct cistpl_manfid_t {
+    u_short	manf;
+    u_short	card;
+} cistpl_manfid_t;
+
+typedef struct cistpl_funcid_t {
+    u_char	func;
+    u_char	sysinit;
+} cistpl_funcid_t;
+
+typedef struct cistpl_funce_t {
+    u_char	type;
+    u_char	data[0];
+} cistpl_funce_t;
+
+typedef struct cistpl_bar_t {
+    u_char	attr;
+    u_int	size;
+} cistpl_bar_t;
+
+typedef struct cistpl_config_t {
+    u_char	last_idx;
+    u_int	base;
+    u_int	rmask[4];
+    u_char	subtuples;
+} cistpl_config_t;
+
+typedef struct cistpl_power_t {
+    u_char	present;
+    u_char	flags;
+    u_int	param[7];
+} cistpl_power_t;
+
+typedef struct cistpl_timing_t {
+    u_int	wait, waitscale;
+    u_int	ready, rdyscale;
+    u_int	reserved, rsvscale;
+} cistpl_timing_t;
+
+#define CISTPL_IO_MAX_WIN	16
+
+typedef struct cistpl_io_t {
+    u_char	flags;
+    u_char	nwin;
+    struct {
+	u_int	base;
+	u_int	len;
+    } win[CISTPL_IO_MAX_WIN];
+} cistpl_io_t;
+
+typedef struct cistpl_irq_t {
+    u_int	IRQInfo1;
+    u_int	IRQInfo2;
+} cistpl_irq_t;
+
+#define CISTPL_MEM_MAX_WIN	8
+
+typedef struct cistpl_mem_t {
+    u_char	flags;
+    u_char	nwin;
+    struct {
+	u_int	len;
+	u_int	card_addr;
+	u_int	host_addr;
+    } win[CISTPL_MEM_MAX_WIN];
+} cistpl_mem_t;
+
+typedef struct cistpl_cftable_entry_t {
+    u_char		index;
+    u_short		flags;
+    u_char		interface;
+    cistpl_power_t	vcc, vpp1, vpp2;
+    cistpl_timing_t	timing;
+    cistpl_io_t		io;
+    cistpl_irq_t	irq;
+    cistpl_mem_t	mem;
+    u_char		subtuples;
+} cistpl_cftable_entry_t;
+
+typedef struct cistpl_cftable_entry_cb_t {
+    u_char		index;
+    u_int		flags;
+    cistpl_power_t	vcc, vpp1, vpp2;
+    u_char		io;
+    cistpl_irq_t	irq;
+    u_char		mem;
+    u_char		subtuples;
+} cistpl_cftable_entry_cb_t;
+
+typedef struct cistpl_device_geo_t {
+    u_char		ngeo;
+    struct {
+	u_char		buswidth;
+	u_int		erase_block;
+	u_int		read_block;
+	u_int		write_block;
+	u_int		partition;
+	u_int		interleave;
+    } geo[CISTPL_MAX_DEVICES];
+} cistpl_device_geo_t;
+
+typedef struct cistpl_vers_2_t {
+    u_char	vers;
+    u_char	comply;
+    u_short	dindex;
+    u_char	vspec8, vspec9;
+    u_char	nhdr;
+    u_char	vendor, info;
+    char	str[244];
+} cistpl_vers_2_t;
+
+typedef struct cistpl_org_t {
+    u_char	data_org;
+    char	desc[30];
+} cistpl_org_t;
+
+typedef struct cistpl_format_t {
+    u_char	type;
+    u_char	edc;
+    u_int	offset;
+    u_int	length;
+} cistpl_format_t;
+
+typedef union cisparse_t {
+    cistpl_device_t		device;
+    cistpl_checksum_t		checksum;
+    cistpl_longlink_t		longlink;
+    cistpl_longlink_mfc_t	longlink_mfc;
+    cistpl_vers_1_t		version_1;
+    cistpl_altstr_t		altstr;
+    cistpl_jedec_t		jedec;
+    cistpl_manfid_t		manfid;
+    cistpl_funcid_t		funcid;
+    cistpl_funce_t		funce;
+    cistpl_bar_t		bar;
+    cistpl_config_t		config;
+    cistpl_cftable_entry_t	cftable_entry;
+    cistpl_cftable_entry_cb_t	cftable_entry_cb;
+    cistpl_device_geo_t		device_geo;
+    cistpl_vers_2_t		vers_2;
+    cistpl_org_t		org;
+    cistpl_format_t		format;
+} cisparse_t;
+
+typedef struct tuple_t {
+    u_int	Attributes;
+    cisdata_t 	DesiredTuple;
+    u_int	Flags;		/* internal use */
+    u_int	LinkOffset;	/* internal use */
+    u_int	CISOffset;	/* internal use */
+    cisdata_t	TupleCode;
+    cisdata_t	TupleLink;
+    cisdata_t	TupleOffset;
+    cisdata_t	TupleDataMax;
+    cisdata_t	TupleDataLen;
+    cisdata_t	*TupleData;
+} tuple_t;
+
+#define TUPLE_RETURN_COMMON	0x02
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+    u_int	Chains;
+} cisinfo_t;
+
+#define CISTPL_MAX_CIS_SIZE	0x200
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+    u_int	Length;
+    cisdata_t	Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+/* bulkmem.h */
+
+typedef struct region_info_t {
+    u_int		Attributes;
+    u_int		CardOffset;
+    u_int		RegionSize;
+    u_int		AccessSpeed;
+    u_int		BlockSize;
+    u_int		PartMultiple;
+    u_char		JedecMfr, JedecInfo;
+    memory_handle_t	next;
+} region_info_t;
+
+
+/* ds.h */
+
+typedef struct tuple_parse_t {
+    tuple_t		tuple;
+    cisdata_t		data[255];
+    cisparse_t		parse;
+} tuple_parse_t;
+
+typedef struct win_info_t {
+    window_handle_t	handle;
+    win_req_t		window;
+    memreq_t		map;
+} win_info_t;
+    
+typedef struct bind_info_t {
+    dev_info_t		dev_info;
+    u_char		function;
+    struct dev_link_t	*instance;
+    char		name[DEV_NAME_LEN];
+    u_short		major, minor;
+    void		*next;
+} bind_info_t;
+
+typedef struct mtd_info_t {
+    dev_info_t		dev_info;
+    u_int		Attributes;
+    u_int		CardOffset;
+} mtd_info_t;
+
+typedef union ds_ioctl_arg_t {
+    servinfo_t		servinfo;
+    adjust_t		adjust;
+    config_info_t	config;
+    tuple_t		tuple;
+    tuple_parse_t	tuple_parse;
+    client_req_t	client_req;
+    cs_status_t		status;
+    conf_reg_t		conf_reg;
+    cisinfo_t		cisinfo;
+    region_info_t	region;
+    bind_info_t		bind_info;
+    mtd_info_t		mtd_info;
+    win_info_t		win_info;
+    cisdump_t		cisdump;
+} ds_ioctl_arg_t;
+
+#define DS_GET_CONFIGURATION_INFO	_IOWR('d', 3, config_info_t)
+#define DS_GET_FIRST_TUPLE		_IOWR('d', 4, tuple_t)
+#define DS_GET_TUPLE_DATA		_IOWR('d', 6, tuple_parse_t)
+#define DS_PARSE_TUPLE			_IOWR('d', 7, tuple_parse_t)
+
+
+#endif
--- hal-0.4.0/hald/linux/osspec.c.pcmcia-support	2004-10-22 22:06:52.542603303 -0400
+++ hal-0.4.0/hald/linux/osspec.c	2004-10-22 22:06:52.569601669 -0400
@@ -458,10 +458,22 @@
 			gchar *normalized_target;
 
 			g_snprintf (path, SYSFS_PATH_MAX, "%s/class/%s/%s/device", sysfs_mount_path, f, f1);
-			if ((target = g_file_read_link (path, NULL)) != NULL) {
+			/* Accept net devices without device links too, they may be coldplugged PCMCIA devices */
+			if (((target = g_file_read_link (path, NULL)) != NULL)
+#if PCMCIA_SUPPORT_ENABLE
+				|| !strcmp (f, "net"))
+#endif
+			{
 				g_snprintf (path1, SYSFS_PATH_MAX, "%s/class/%s/%s", sysfs_mount_path, f, f1);
-				normalized_target = get_normalized_path (path1, target);
-				g_free (target);
+				if (target) {
+					normalized_target = get_normalized_path (path1, target);
+					g_free (target);
+				}
+#if PCMCIA_SUPPORT_ENABLE
+				else {
+					normalized_target = g_strdup (path1);
+				}
+#endif
 
 				/*printf ("%s -> (%s, %s)\n", normalized_target, path1, f);*/
 				g_hash_table_insert (sysfs_to_class_in_devices_map, 
--- hal-0.4.0/hald/linux/pcmcia_utils.h.pcmcia-support	2004-10-22 22:06:52.571601548 -0400
+++ hal-0.4.0/hald/linux/pcmcia_utils.h	2004-10-22 22:48:19.015180824 -0400
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * CVSID: $Id: pcmcia_utils.h,v 1.19 2004/10/14 18:41:27 david Exp $
+ *
+ * PCMCIA Card utilities
+ *
+ * Copyright (C) 2003 Dan Williams <dcbw at redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ **************************************************************************/
+
+#ifndef PCMCIA_UTILS_H
+#define PCMCIA_UTILS_H
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "pcmcia_cs.h"
+
+#define PCMCIA_MAX_SOCKETS 8
+
+
+typedef enum PCMCIA_card_type {
+	PCMCIA_TYPE_MULTIFUNCTION = 0,
+	PCMCIA_TYPE_MEMORY,
+	PCMCIA_TYPE_SERIAL,
+	PCMCIA_TYPE_PARALLEL,
+	PCMCIA_TYPE_FIXED_DISK,
+	PCMCIA_TYPE_VIDEO,
+	PCMCIA_TYPE_NETWORK,
+	PCMCIA_TYPE_AIMS,
+	PCMCIA_TYPE_SCSI,
+	PCMCIA_TYPE_INVALID	/* should always be last */
+} PCMCIA_card_type;
+
+
+typedef struct pcmcia_stab_entry {
+	int				socket;
+	PCMCIA_card_type	type;
+	char				*driver;
+	char				*dev;
+} pcmcia_stab_entry;
+
+typedef struct pcmcia_card_info {
+	int				socket;
+	PCMCIA_card_type	type;
+	char				*productid_1;
+	char				*productid_2;
+	char				*productid_3;
+	char				*productid_4;
+	int				manfid_1;
+	int				manfid_2;
+} pcmcia_card_info;
+
+
+int pcmcia_socket_open (int socket);
+int pcmcia_get_tuple(int fd, cisdata_t code, ds_ioctl_arg_t *arg);
+
+const char *pcmcia_card_type_string_from_type (const PCMCIA_card_type type);
+PCMCIA_card_type pcmcia_card_type_from_type_string (const char *string);
+
+pcmcia_stab_entry *pcmcia_stab_entry_get (int socket);
+void pcmcia_stab_entry_free (pcmcia_stab_entry *entry);
+pcmcia_stab_entry *pcmcia_get_stab_entry_for_device (const char *interface);
+
+pcmcia_card_info *pcmcia_card_info_get (int socket);
+void pcmcia_card_info_free (pcmcia_card_info *info);
+
+#endif
--- hal-0.4.0/hald/linux/net_class_device.c.pcmcia-support	2004-10-14 14:41:27.000000000 -0400
+++ hal-0.4.0/hald/linux/net_class_device.c	2004-10-22 22:49:44.259023884 -0400
@@ -58,6 +58,10 @@
 #include "class_device.h"
 #include "common.h"
 
+#if PCMCIA_SUPPORT_ENABLE
+#include "pcmcia_utils.h"
+#endif
+
 /**
  * @defgroup HalDaemonLinuxNet Network class
  * @ingroup HalDaemonLinux
@@ -513,6 +517,9 @@
 	dbus_bool_t is_80211 = FALSE;
 	int ifindex;
 	int flags;
+#if PCMCIA_SUPPORT_ENABLE
+	pcmcia_stab_entry *entry;
+#endif
 
 	hal_device_property_set_string (d, "net.linux.sysfs_path", sysfs_path);
 	hal_device_property_set_string (d, "net.interface",
@@ -603,6 +610,69 @@
 		hal_device_property_set_string (d, "info.category", "net.80203");
 		hal_device_add_capability (d, "net.80203");
 	}
+
+#if PCMCIA_SUPPORT_ENABLE
+	/* Add PCMCIA specific entries for PCMCIA cards */
+	if ((entry = pcmcia_get_stab_entry_for_device (class_device->name))) {
+		pcmcia_card_info *info = pcmcia_card_info_get (entry->socket);
+		if (info && (info->socket >= 0)) {
+			const char *type;
+			HalDevice *parent;
+
+			hal_device_property_set_string (d, "info.bus", "pcmcia");
+			if (entry->driver)
+				hal_device_property_set_string (d, "info.driver", entry->driver);
+
+			if (info->productid_1 && strlen (info->productid_1))
+				hal_device_property_set_string (d, "pcmcia.productid_1", info->productid_1);
+			if (info->productid_2 && strlen (info->productid_2))
+				hal_device_property_set_string (d, "pcmcia.productid_2", info->productid_2);
+			if (info->productid_3 && strlen (info->productid_3))
+				hal_device_property_set_string (d, "pcmcia.productid_3", info->productid_3);
+			if (info->productid_4 && strlen (info->productid_4))
+				hal_device_property_set_string (d, "pcmcia.productid_4", info->productid_4);
+
+			if ((type = pcmcia_card_type_string_from_type (info->type)))
+				hal_device_property_set_string (d, "pcmcia.function", type);
+
+			hal_device_property_set_int (d, "pcmcia.manfid_1", info->manfid_1);
+			hal_device_property_set_int (d, "pcmcia.manfid_2", info->manfid_2);
+			hal_device_property_set_int (d, "pcmcia_socket.number", info->socket);
+
+			/* Provide best-guess of vendor, goes in Vendor property; 
+			 * .fdi files can override this */
+			if (info->productid_1 != NULL) {
+				hal_device_property_set_string (d, "info.vendor", info->productid_1);
+			} else {
+				char namebuf[50];
+				snprintf (namebuf, sizeof(namebuf), "Unknown (0x%04x)", info->manfid_1);
+				hal_device_property_set_string (d, "info.vendor", namebuf);
+			}
+
+			/* Provide best-guess of name, goes in Product property; 
+			 * .fdi files can override this */
+			if (info->productid_2 != NULL) {
+				hal_device_property_set_string (d, "info.product", info->productid_2);
+			} else {
+				char namebuf[50];
+				snprintf (namebuf, sizeof(namebuf), "Unknown (0x%04x)", info->manfid_2);
+				hal_device_property_set_string (d, "info.product", namebuf);
+			}
+
+			/* Reparent PCMCIA devices to be under their socket */
+			parent = hal_device_store_match_key_value_int (hald_get_gdl (), 
+									      "pcmcia_socket.number", 
+									      info->socket);
+			if (parent)
+				hal_device_property_set_string (d, "info.parent",
+						hal_device_property_get_string (parent, "info.udi"));
+
+			pcmcia_card_info_free (info);
+		}
+
+		pcmcia_stab_entry_free (entry);
+	}
+#endif
 }
 
 static dbus_bool_t
@@ -611,6 +681,9 @@
 {
 	gboolean accept;
 	struct sysfs_attribute *attr = NULL;
+#if PCMCIA_SUPPORT_ENABLE
+	pcmcia_stab_entry *entry = NULL;
+#endif
 
 	accept = TRUE;
 
@@ -637,12 +710,32 @@
 	}
 
 	/* 1 is the type for ethernet (incl. wireless) devices */
-	if (attr->value[0] == '1') {
-		accept = TRUE;
+	if (attr->value[0] != '1') {
+		accept = FALSE;
 		goto out;
+	}
+
+#if PCMCIA_SUPPORT_ENABLE
+	/* Allow 'net' devices without a sysdevice only if they
+	 * are backed by real hardware (like PCMCIA cards).
+	 */
+	if ((entry = pcmcia_get_stab_entry_for_device (class_device->name))) {
+		pcmcia_card_info *info = pcmcia_card_info_get (entry->socket);
+		if (info && (info->socket >= 0)) {
+			/* Ok, we're a PCMCIA card */
+			pcmcia_card_info_free (info);
+			accept = TRUE;
+			goto out;
+		} else {
+			accept = FALSE;
+			goto out;
+		}
+		pcmcia_stab_entry_free (entry);
 	} else {
 		accept = FALSE;
+		goto out;
 	}
+#endif
 
 out:
 	return accept;
--- hal-0.4.0/hald/linux/pcmcia_utils.c.pcmcia-support	2004-10-22 22:06:52.577601185 -0400
+++ hal-0.4.0/hald/linux/pcmcia_utils.c	2004-10-22 22:49:07.184266770 -0400
@@ -0,0 +1,314 @@
+/***************************************************************************
+ * CVSID: $Id: pcmcia_utils.h,v 1.19 2004/10/14 18:41:27 david Exp $
+ *
+ * PCMCIA Card utilities
+ *
+ * Copyright (C) 2003 Dan Williams <dcbw at redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ *
+ * Some of this code was derived from pcmcia-cs code, originally
+ * developed by David A. Hinds <dahinds at users.sourceforge.net>.
+ * Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds.
+ * All Rights Reserved.  It has been modified for integration into HAL
+ * by Dan Williams and is covered by the GPL version 2 license.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "pcmcia_utils.h"
+
+static char *pcmcia_card_types[] = {
+	"multifunction", "memory", "serial", "parallel",
+	"fixed disk", "video", "network", "AIMS", "SCSI"
+};
+
+static int pcmcia_major = -1;
+
+static int pcmcia_lookup_dev(void)
+{
+	FILE *f;
+	int n;
+	char s[32], t[32];
+    
+	f = fopen("/proc/devices", "r");
+	if (f == NULL)
+		return -errno;
+	while (fgets(s, 32, f) != NULL) {
+		if (sscanf(s, "%d %s", &n, t) == 2)
+			if (strcmp("pcmcia", t) == 0)
+				break;
+	}
+	fclose(f);
+	if (strcmp ("pcmcia", t) == 0)
+		return n;
+	else
+		return -ENODEV;
+}
+
+int pcmcia_socket_open (int socket)
+{
+	static char *paths[] = {
+		"/var/lib/pcmcia", "/var/run", "/dev", "/tmp", NULL
+	};
+	int fd;
+	char **p, fn[64];
+	dev_t dev;
+
+	if ((socket < 0) || (socket > PCMCIA_MAX_SOCKETS))
+		return -1;
+
+	if (pcmcia_major < 0)
+	{
+		pcmcia_major = pcmcia_lookup_dev();
+		if (pcmcia_major < 0) {
+			if (pcmcia_major == -ENODEV)
+				fprintf (stderr, "no pcmcia driver in /proc/devices\n");
+			else
+				fprintf (stderr, "could not open /proc/devices");
+		}
+	}
+	dev = (pcmcia_major<<8) + socket;
+
+	for (p = paths; *p; p++) {
+		sprintf(fn, "%s/hal-%d", *p, getpid());
+		if (mknod(fn, (S_IFCHR | S_IREAD | S_IWRITE), dev) == 0) {
+			fd = open(fn, O_RDONLY);
+			unlink(fn);
+			if (fd >= 0)
+				return fd;
+			if (errno == ENODEV)
+				break;
+		}
+	}
+	return -1;
+}
+
+
+int pcmcia_get_tuple(int fd, cisdata_t code, ds_ioctl_arg_t *arg)
+{
+	arg->tuple.DesiredTuple = code;
+	arg->tuple.Attributes = TUPLE_RETURN_COMMON;
+	arg->tuple.TupleOffset = 0;
+	if (    (ioctl(fd, DS_GET_FIRST_TUPLE, arg) == 0)
+		&& (ioctl(fd, DS_GET_TUPLE_DATA, arg) == 0)
+		&& (ioctl(fd, DS_PARSE_TUPLE, arg) == 0))
+		return 0;
+	else
+		return -1;
+}
+
+
+pcmcia_card_info *pcmcia_card_info_get (int socket)
+{
+	int fd;
+	pcmcia_card_info *info = NULL;
+
+	if ((socket < 0) || (socket > PCMCIA_MAX_SOCKETS))
+		return NULL;
+
+	fd = pcmcia_socket_open (socket);
+	if (fd >= 0) {
+		ds_ioctl_arg_t   arg;
+		cistpl_vers_1_t *vers = &arg.tuple_parse.parse.version_1;
+		cistpl_manfid_t *manfid = &arg.tuple_parse.parse.manfid;
+		cistpl_funcid_t *funcid = &arg.tuple_parse.parse.funcid;
+		config_info_t    config;
+
+		/* Ignore CardBus cards and empty slots */
+		if (ioctl(fd, DS_GET_CONFIGURATION_INFO, &config) == 0)
+			goto out;
+		if (config.IntType == INT_CARDBUS)
+			goto out;
+
+		if (pcmcia_get_tuple(fd, CISTPL_VERS_1, &arg) != 0)
+			goto out;
+
+		if (!(info = calloc (1, sizeof (pcmcia_card_info))))
+			goto out;
+
+		info->socket = socket;
+
+		if (vers->ns >= 1)
+			info->productid_1 = strdup (vers->str+vers->ofs[0]);
+		if (vers->ns >= 2)
+			info->productid_2 = strdup (vers->str+vers->ofs[1]);
+		if (vers->ns >= 3)
+			info->productid_3 = strdup (vers->str+vers->ofs[2]);
+		if (vers->ns >= 4)
+			info->productid_4 = strdup (vers->str+vers->ofs[3]);
+
+		if (pcmcia_get_tuple(fd, CISTPL_FUNCID, &arg) == 0)
+			info->type = funcid->func;
+
+		if (pcmcia_get_tuple(fd, CISTPL_MANFID, &arg) == 0) {
+			info->manfid_1 = manfid->manf;
+			info->manfid_2 = manfid->card;
+		}
+		close (fd);
+	}
+
+out:
+	return (info);
+}
+
+
+void pcmcia_card_info_free (pcmcia_card_info *info)
+{
+	if (!info) return;
+
+	info->socket = -1;
+	info->type = PCMCIA_TYPE_INVALID;
+	free (info->productid_1);
+	free (info->productid_2);
+	free (info->productid_3);
+	free (info->productid_4);
+	info->manfid_1 = -1;
+	info->manfid_2 = -1;
+}
+
+const char *pcmcia_card_type_string_from_type (const PCMCIA_card_type type)
+{
+	/* basically, ensure we don't go out of the array's bounds */
+	if ((type < PCMCIA_TYPE_MULTIFUNCTION) || (type >= PCMCIA_TYPE_INVALID)) return NULL;
+
+	return pcmcia_card_types[type];
+}
+
+PCMCIA_card_type pcmcia_card_type_from_type_string (const char *string)
+{
+	PCMCIA_card_type i;
+
+	if (!string) return PCMCIA_TYPE_INVALID;
+
+	for (i = PCMCIA_TYPE_MULTIFUNCTION; i < PCMCIA_TYPE_INVALID; i++) {
+		if (!strcmp (string, pcmcia_card_types[i]))
+			return i;
+	}
+	return PCMCIA_TYPE_INVALID;
+}
+
+
+static inline int whack_newline (char *buf)
+{
+	int len;
+
+	if (!buf)
+		return 0;
+
+	len = strlen (buf);
+	if ((buf[len-1] == '\n') || (buf[len-1] == '\r')) {
+		buf[len-1] = '\0';
+		len--;
+	}
+
+	return len;
+}
+
+
+pcmcia_stab_entry *pcmcia_stab_entry_get (int socket)
+{
+	FILE *f;
+	pcmcia_stab_entry *entry = NULL;
+
+	if ((socket < 0) || (socket > PCMCIA_MAX_SOCKETS))
+		return NULL;
+
+	if ((f = fopen ("/var/lib/pcmcia/stab", "r"))) {
+		char	buf[200];
+
+		while (fgets (buf, 200, f) && !feof (f)) {
+			char match[50];
+
+			buf[199] = '\0';
+			whack_newline (buf);
+
+			snprintf (match, 49, "Socket %d", socket);
+			if (!strncmp (buf, match, strlen (match))) {
+				/* Ok, found our socket */
+				if (fgets (buf, 200, f) && !feof (f)) {
+					buf[199] = '\0';
+					whack_newline (buf);
+					if (strncmp (buf, "Socket", 6)) {
+						/* Got our card */
+						int s;
+						char func[50];
+						char driver[50];
+						int g;
+						char dev[50];
+
+						if (sscanf (buf, "%d\t%s\t%s\t%d\t%s", &s, &func, &driver, &g, &dev) == 5) {
+							PCMCIA_card_type t = pcmcia_card_type_from_type_string (func);
+							if (t != PCMCIA_TYPE_INVALID) {
+								entry = calloc (1, sizeof (pcmcia_stab_entry));
+								entry->socket = s;
+								entry->type = t;
+								entry->driver = strdup (driver);
+								entry->dev = strdup (dev);
+							}
+							break;
+						}
+					}
+				}
+			}
+		}
+		fclose (f);
+	}
+
+	return (entry);
+}
+
+
+void pcmcia_stab_entry_free (pcmcia_stab_entry *entry)
+{
+	if (!entry) return;
+
+	entry->socket = -1;
+	entry->type = PCMCIA_TYPE_INVALID;
+	free (entry->driver);
+	free (entry->dev);
+}
+
+
+pcmcia_stab_entry *pcmcia_get_stab_entry_for_device (const char *interface)
+{
+	pcmcia_stab_entry *entry = NULL;
+	int i;
+
+	if (!interface) return 0;
+
+	for (i = 0; i < PCMCIA_MAX_SOCKETS; i++)
+	{
+		if ((entry = pcmcia_stab_entry_get (i)))
+		{
+			if (!strcmp (interface, entry->dev))
+				break;
+			pcmcia_stab_entry_free (entry);
+		}
+	}
+
+	return (entry);
+}
+
--- hal-0.4.0/hald/Makefile.am.pcmcia-support	2004-10-14 15:16:33.000000000 -0400
+++ hal-0.4.0/hald/Makefile.am	2004-10-22 22:06:52.567601790 -0400
@@ -60,6 +60,9 @@
 
 #					linux/ieee1394_host_class_device.c
 
+if PCMCIA_SUPPORT_ENABLE
+hald_SOURCES += linux/pcmcia_utils.c linux/pcmcia_utils.h linux/pcmcia_cs.h
+endif
 
 hald_SOURCES +=                                                         \
         linux/libsysfs/libsysfs.h                                       \
--- hal-0.4.0/configure.in.pcmcia-support	2004-10-14 18:57:28.000000000 -0400
+++ hal-0.4.0/configure.in	2004-10-22 22:06:52.579601064 -0400
@@ -71,6 +71,13 @@
 AM_CONDITIONAL(FSTAB_SYNC_ENABLED, test x$enable_fstab_sync = xyes)
 
 
+AC_ARG_ENABLE(pcmcia-support,         [  --enable-pcmcia-support     Extended PCMCIA card support],enable_pcmcia_support=yes,enable_pcmcia_support=no)
+if test "x$enable_pcmcia_support" = "xyes" ; then
+   AC_DEFINE(PCMCIA_SUPPORT_ENABLE,1,[Whether PCMCIA card workarounds should be used (for kernels that don't have a sysfsized PCMCIA layer)])
+fi
+AC_SUBST(PCMCIA_SUPPORT_ENABLE)
+AM_CONDITIONAL(PCMCIA_SUPPORT_ENABLE, test x$enable_pcmcia_support = xyes)
+
 AC_ARG_ENABLE(hotplug_map,         [  --enable-hotplug-map    Install hotplug-map callout],enable_hotplug_map=yes,enable_hotplug_map=no)
 if test "x$enable_hotplug_map" = "xyes" ; then
    AC_DEFINE(HOTPLUG_MAP_ENABLED,1,[Whether hotplug-map callout should be installed])
@@ -433,7 +440,9 @@
         hald pidfile:             ${HALD_PID_FILE}
         Building SELinux support: ${have_selinux}
 
-        install fstab-sync:                     ${enable_fstab_sync}
+        install fstab-sync:       ${enable_fstab_sync}
+
+        Extended PCMCIA support:  ${enable_pcmcia_support}
 
         install hal-hotplug-map:  ${enable_hotplug_map}"
 
--- hal-0.4.0/config.h.in.pcmcia-support	2004-10-14 18:58:20.000000000 -0400
+++ hal-0.4.0/config.h.in	2004-10-22 22:06:52.578601125 -0400
@@ -105,6 +105,10 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
+/* Whether PCMCIA card workarounds should be used (for kernels that don't have
+   a sysfsized PCMCIA layer) */
+#undef PCMCIA_SUPPORT_ENABLE
+
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
-------------- next part --------------
_______________________________________________
hal mailing list
hal at freedesktop.org
http://freedesktop.org/mailman/listinfo/hal


More information about the Hal mailing list