hal/hald/linux net_class_device.c, 1.20, 1.21 osspec.c, 1.51, 1.52 pcmcia_cs.h, NONE, 1.1 pcmcia_utils.c, NONE, 1.1 pcmcia_utils.h, NONE, 1.1

David Zeuthen david at freedesktop.org
Tue Oct 26 10:35:23 PDT 2004


Update of /cvs/hal/hal/hald/linux
In directory gabe:/tmp/cvs-serv3665/hald/linux

Modified Files:
	net_class_device.c osspec.c 
Added Files:
	pcmcia_cs.h pcmcia_utils.c pcmcia_utils.h 
Log Message:
2004-10-26  David Zeuthen  <davidz at redhat.com>

	Patch from Dan Williams <dcbw at redhat.com> to add support for 
	integration with cardmgr.

	* configure.in: Add --enable-pcmcia-support and --with-stab-file
	options
	
	* hald/Makefile.am: Conditionally include linux/pcmcia_utils.c
	linux/pcmcia_utils.h linux/pcmcia_cs.h

	* hald/linux/net_class_device.c
	(net_class_pre_process): Check driver link and set net.linux.driver
	properties (me); add appropriate PCMCIA properties if applicable
	(net_class_accept): Only accept network devices with device links as
	well as PCMCIA devices
	(net_class_compute_udi): Fix a typo (me)
	
	* hald/linux/osspec.c
	(compute_coldplug_list): Accept network devices without device link
	
	* hald/linux/pcmcia_cs.h: New file

	* hald/linux/pcmcia_utils.c: New file
	
	* hald/linux/pcmcia_utils.h: New file



Index: net_class_device.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/net_class_device.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- net_class_device.c	21 Oct 2004 21:27:44 -0000	1.20
+++ net_class_device.c	26 Oct 2004 17:35:21 -0000	1.21
@@ -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
@@ -509,10 +513,14 @@
 	int media_type = 0;
 	const char *media;
 	char wireless_path[SYSFS_PATH_MAX];
+	char driver_path[SYSFS_PATH_MAX];
 	dbus_bool_t is_80211 = FALSE;
 	int ifindex;
 	int flags;
 	struct stat statbuf;
+#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",
@@ -526,6 +534,16 @@
 		is_80211 = TRUE;
 	}
 
+	/* Check driver link (may be unavailable for PCMCIA devices) */
+	snprintf (driver_path, SYSFS_PATH_MAX, "%s/driver", sysfs_path);
+	if (stat (driver_path, &statbuf) == 0) {
+		char buf[256];
+		memset (buf, '\0', sizeof (buf));
+		if (readlink (driver_path, buf, sizeof (buf) - 1) > 0) {
+			hal_device_property_set_string (d, "net.linux.driver", get_last_element (buf));
+		}
+	}
+
 	attr = sysfs_get_classdev_attr (class_device, "address");
 	if (attr != NULL) {
 		address = g_strstrip (g_strdup (attr->value));
@@ -596,6 +614,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, "net.linux.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
@@ -604,6 +685,9 @@
 {
 	gboolean accept;
 	struct sysfs_attribute *attr = NULL;
+#if PCMCIA_SUPPORT_ENABLE
+	pcmcia_stab_entry *entry = NULL;
+#endif
 
 	accept = TRUE;
 
@@ -630,12 +714,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 */
+			accept = TRUE;
+		} else {
+			accept = FALSE;
+		}
+		
+		pcmcia_card_info_free (info);
+		pcmcia_stab_entry_free (entry);
 		goto out;
 	} else {
 		accept = FALSE;
+		goto out;
 	}
+#endif
 
 out:
 	return accept;
@@ -658,7 +762,7 @@
 	if (append_num == -1)
 		format = "/org/freedesktop/Hal/devices/net-%s";
 	else
-		format = "/org/freedesktop/Hal/devices_net-%s-%d";
+		format = "/org/freedesktop/Hal/devices/net-%s-%d";
 
 	snprintf (buf, 256, format,
 		  hal_device_property_get_string (d, "net.address"),

Index: osspec.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/osspec.c,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -d -r1.51 -r1.52
--- osspec.c	25 Oct 2004 15:35:49 -0000	1.51
+++ osspec.c	26 Oct 2004 17:35:21 -0000	1.52
@@ -458,10 +458,23 @@
 			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, 

--- NEW FILE: pcmcia_cs.h ---
/***************************************************************************
 * CVSID: $Id: pcmcia_cs.h,v 1.1 2004/10/26 17:35:21 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

--- NEW FILE: pcmcia_utils.c ---
/***************************************************************************
 * CVSID: $Id: pcmcia_utils.c,v 1.1 2004/10/26 17:35:21 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 (PCMCIA_STAB_FILE, "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);
}


--- NEW FILE: pcmcia_utils.h ---
/***************************************************************************
 * CVSID: $Id: pcmcia_utils.h,v 1.1 2004/10/26 17:35:21 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




More information about the hal-commit mailing list