[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